2017-09-24 9 views
3

この非コンパイルスニペットを見てみましょう。呼び出しのための便利な構文でメンバー関数ポインタを持つ関数を特殊化することは可能ですか?

struct Object { 
    template <RETURN (OBJECT::*MEMFN)(PARAMETERS...), typename RETURN, typename OBJECT, typename ...PARAMETERS> 
    void call() { 
    } 
}; 

struct Foo { 
    void fn(); 
}; 

int main() { 
    Object o; 
    o.call<&Foo::fn>(); 
} 

基本的に、私が達成したいことは呼び出すために便利な構文で、メンバ関数ポインタのいずれかの種類に特化した、機能(Object::call)を持つことです。

私が見つけた最寄のソリューションは非常に醜いである、このです:

struct Object { 
}; 

template <typename MEMFNTYPE, MEMFNTYPE MEMFN> 
struct Caller; 

template <typename RETURN, typename OBJECT, typename ...PARAMETERS, RETURN (OBJECT::*MEMFN)(PARAMETERS...)> 
struct Caller<RETURN (OBJECT::*)(PARAMETERS...), MEMFN> { 
    Object *object; 

    Caller(Object &o) : object(&o) { } 

    void call() { 
     // I have the necessary information here: the member function pointer as template parameter, and a pointer to Object 
    } 
}; 

struct Foo { 
    void fn(); 
}; 

int main() { 
    Object o; 

    Caller<decltype(&Foo::fn), &Foo::fn>(o).call(); 
} 

は、この問題のためのよりよい解決策はありますか?

(私はこれをやろうとしているある理由は、私は他のメンバ関数のためのラッパー関数(call)を作成したいということです)


Kerrek SBがautoを使用して提案し、私が試してみましたこの:?

struct Object { 
    template <auto MEMFN> 
    void call(); 

    template <auto MEMFN, typename RETURN, typename OBJECT, typename ...PARAMETERS> 
    void call<RETURN (OBJECT::*MEMFN)(PARAMETERS...)>() { 
    } 
}; 

struct Foo { 
    void fn(); 
}; 

int main() { 
    Object o; 
    o.call<&Foo::fn>(); 
} 

しかし、これは(私が(代わりにauto MEMFNのテンプレートパラメータリストには異なるMEMFNを追加する必要があります)コンパイルされません:

t2.cpp:6:7: error: parse error in template argument list 
    void call<RETURN (OBJECT::*MEMFN)(PARAMETERS...)>() { 
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
t2.cpp:6:52: error: non-class, non-variable partial specialization ‘call<<expression error> >’ is not allowed 
    void call<RETURN (OBJECT::*MEMFN)(PARAMETERS...)>() { 
+1

'template void call();'を実行してからspecializeします。 –

+0

'std :: bind()'は実際に何をしていませんか? – user0042

+0

'std :: invoke'を求めていますか? http://en.cppreference.com/w/cpp/utility/functional/invoke –

答えて

2

コメントで示唆したように、C++ 17ソリューションを受け入れるとautoはあなたの友人です。そしてそう<type_traits>if constexprされています

#include <type_traits> 
#include <iostream> 

struct Object { 
    template <auto MEMFN> 
    void call() { 
     if constexpr (std::is_member_function_pointer_v<decltype(MEMFN)>) 
      std::cout << "Is member\n"; 
    } 
}; 

struct Foo { 
    void fn(); 
}; 

int main() { 
    Object o; 
    o.call<&Foo::fn>(); 
} 

は、関数本体は型特性は、それが実際にそれで言うならば、メンバ関数ポインタとしてパラメータを扱うコードを発行します。専門性は必要ありません。

+0

ありがとう! 'call'が実際にMEMFNと同じパラメータリストを持つバージョンを作ることは可能ですか? MEMFNからOBJECT/RETURNを読み込むのはテンプレートのトリッキーなことがありますが、MEMFNから "PARAMETERS ..."を読む方法がわかりません。 – geza

+0

@geza - (いくつかの点で)可能ですが、どのように使いたいかにかかっているかどうかは決まります。 – StoryTeller

関連する問題