14

テンプレート引数は、メンバー関数へのポインターである可能性があることが知られています。

だから私は書くことができます:

struct Bar
{
    int fun(float x);
};

template <int (Bar::*FUN)(float)>
struct Foo
{ /*...*/ };

typedef Foo<&Bar::fun> FooBar;

Barしかし、型自体をテンプレート引数にしたい場合はどうなりますか?

template <typename B, int (B::*FUN)(float)>
struct Foo
{ /*...*/ };

typedef Foo<Bar, &Bar::fun> FooBar;

さて、使うときはBar二度書く必要があります!

私の質問は、コンパイラにクラスタイプを自動的に推測させる方法はありますか?

目的は、これが正しく機能することです。

typedef Foo<&Bar::fun> FooBar;
typedef Foo<&Moo::fun> FooMoo;
4

2 に答える 2

7

簡単な答え:ありません。

問題はtypedef Foo<&Bar::fun> FooBar;、テンプレートが機能するためには、型以外の引数が1つ必要ですが、テンプレートが宣言されているときにその引数の型が不明であり、無効であるということです。一方、型の推定はテンプレートの引数に適用されることはありません(関数テンプレートの引数にのみ適用されますが、これらは関数の引数であり、テンプレートではありません)。

于 2012-07-31T18:00:32.610 に答える
6

おそらくそこにクラス名を書くだけです。ただし、それを本当に避けたい場合は、マクロの邪悪な魔法を使用できます。単純なバージョンはより危険です:

#define TT(X) decltype(X), X

template<typename T,T t>
struct Foo
{ /* ... */ };

struct Bar {
    int fun(float) {}
};

int main() {
    Foo<TT(&Bar::fun)> f;
}

これは、あらゆる種類の非型テンプレートパラメータを受け入れ、Foo実装がメンバーへのポインタでのみ機能する場合、理解しにくいエラーが発生する可能性があります。

少し安全にするには、クラス名を示すメタ関数が必要です。

template<typename T> struct member_ptr_traits;

template<typename Class,typename Ret,typename... Args>
struct member_ptr_traits<Ret (Class::*)(Args...)>
{
    typedef Class class_type;
    typedef Ret return_type;
};

#define TT(X) member_ptr_traits<decltype(X)>::class_type , X

template<typename T,int (T::*FUN)(float)>
struct Foo
{ /* ... */ };

struct Bar {
    int fun(float) {}
};

int main() {
    Foo<TT(&Bar::fun)> f;
}

また、これらは両方ともC ++ 11を使用するため、古いコンパイラでは動作しません。typeofこの単純なバージョンは、古いまたは類似のコンパイラ拡張機能を使用するように書き直すことができます。より安全なバージョンを書き直すには、可変個引数テンプレートをシミュレートする必要があります。

于 2012-07-31T18:26:24.573 に答える