2012-02-19 14 views
2

私はここでスレッドの上に構築しようとしていました:Variable length template arguments list? デフォルトのFunctorクラスを持っているのは学問的なことです。私の目標は、クラス名、メソッド名、(可変長の)引数型があれば、テンプレートargsで指定された型の可変数の引数を取るoperator()メソッドを持つクラスを構築し、ポインタをとり、与えられたメソッドを適用します。したがって、クラスを想像してみて:C++で一般的なFunctorクラス

class MyClass 
{ 
public: 
    float Fraction(float n, int m) 
    { 
     return n/m; 
    } 
    int Increment(int n) 
    { 
     return n+1; 
    } 
} ; 

そしてこうして任意の関数で使用することができるテンプレート化数子クラス:

int k = FunctorClass<MyClass, Increment, int, int /*return type*/> (3); 
assert(k == 4); 
float l = FunctorClass<MyClass, Fraction, float, int, float, /*return type*/> (4,3); 
assert(l == (4/3)); 

は、このようなファンクタクラスを構築することができますか? Sidenote:バリアントテンプレートを使用します(VS2010で構築、テンプレート引数なし) ヘルプありがとう

答えて

2

これは確かに実行可能です。 Boost bind()はこのアプローチをフードの下で使用します。しかし、バリデーションがなければ、完全な一般性を得ることはできません。これは、固定数のテンプレート引数に限定され、サポートしたい引数の数に応じて実装をタイプする必要があるからです。また、右辺値の参照がないと、完璧な転送はできません。

つまり、使用しようとしている方法は機能しません。メンバ関数を記述するときには名前を付けるだけではありません。あなたは正しいメンバーファンクションポイントを取得する必要があります。 &MyClass::Incrementおよび&MyClass::Fraction。メンバ関数がオーバーロードされている場合、それを明確にする必要があります。

静的でないメンバ関数に対してこの関数オブジェクトの使用を有効にしたいように思われるので、メンバ関数を呼び出すオブジェクトも指定する必要があります。これに対する最も合理的なアプローチは、オブジェクトへの参照を関数オブジェクトクラスのコンストラクタ引数として渡し、関数が呼び出されるたびに使用されるように格納することです。つまり、使用方法は若干異なりますが、何らかのファクトリ関数を使用して簡略化することができます。ここでは、様々な事柄を調整し、対応する関数オブジェクトのテンプレートを実装したバージョンは次のとおりです。

#include <cassert> 

// ----------------------------------------------------------------------------- 

template <typename T, T> class FunctorClass; 

template <typename RC, typename Class, 
      RC (Class::*Member)()> 
class FunctorClass<RC (Class::*)(), Member> 
{ 
public: 
    FunctorClass(Class& object): object_(&object) {} 
    RC operator()() const { return (this->object_->*Member)(); } 
private: 
    Class* object_; 
}; 

template <typename RC, typename Class, typename A0, 
      RC (Class::*Member)(A0)> 
class FunctorClass<RC (Class::*)(A0), Member> 
{ 
public: 
    FunctorClass(Class& object): object_(&object) {} 
    RC operator()(A0 a0) const { return (this->object_->*Member)(a0); } 
private: 
    Class* object_; 
}; 

template <typename RC, typename Class, typename A0, typename A1, 
      RC (Class::*Member)(A0, A1)> 
class FunctorClass<RC (Class::*)(A0, A1), Member> 
{ 
public: 
    FunctorClass(Class& object): object_(&object) {} 
    RC operator()(A0 a0, A1 a1) const { return (this->object_->*Member)(a0, a1); } 
private: 
    Class* object_; 
}; 

// ----------------------------------------------------------------------------- 

class MyClass 
{ 
public: 
    int foo() { return 17; } 
    float Fraction(float n, int m) 
    { 
     return n/m; 
    } 
    int Increment(int n) 
    { 
     return n+1; 
    } 
}; 

int main() 
{ 
    MyClass object; 
    int i = FunctorClass<int (MyClass::*)(), &MyClass::foo>(object)(); 
    assert(i == 17); 

    int k = FunctorClass<int (MyClass::*)(int), &MyClass::Increment>(object)(3); 
    assert(k == 4); 
    float l = FunctorClass<float (MyClass::*)(float, int), &MyClass::Fraction>(object)(4,3); 
    assert(l == (4.0f/3)); 
} 
+0

よく考えられた答えをありがとう。はい、私の場合は非静的メンバーのためであり、オブジェクトを送信する必要があります。 これについて少し詳しく説明できますか?また、値の参照がないと完全な転送はできません。 ? ありがとうございました – user1186270

+0

関数テンプレートがrvalue参照をパラメータとして取る場合は、C++ 2011のrvalues参照(ある種の 'T'では' T && ')と特別なテンプレート推論規則がサポートされています。これにより、パラメータがどのように渡されたか(すなわち、左辺値から来たものか、一時的なものから来たものか)を取得し、これをラップされた関数に転送することができます。 temporaryはコピーせずに通過できるので、C++ 2003では不可能な特定のコピーを防ぐことができます。しかし、完全な議論はかなり長い記事です。 –

+0

@ user1186270:Dietmarは正しいです。それは確かにかなり長い記事にします。幸いにも誰かがすでにここに書いています:http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx – ForeverLearning

0

私はあなたがこれをやってのけるvariadicsが必要になるかわかりません。彼らはそのような機能シグネチャといくつかのデータ・メンバーとしての部分的な実装を含むことができ、

template < typename RETURN_TYPE > 
class iFunctor abstract { 

    public: 

     virtual RETURN_TYPE operator() (void) = 0; 

}; 

抽象インタフェースが本格的なクラスはない...次のインタフェースを考えます。テンプレートを使用すると、戻り値の型を一般化できます。しかしあなたが言う議論のリストはどうですか?

インターフェイスにコンストラクタがないことに注意してください。あなたの具体的なクラス(または派生クラス)では、あなたは...そうのように、コンストラクタにあなたは、コンストラクタを介してケースバイケースで引数リストを扱う

template < typename TYPE > 
class ConcreteFunctor_add : public iFunctor <TYPE> { 

    private: 

     int A; 
     int B; 

    public: 

     explicit ConcreteFunctor_add (const int &a, const int &b) : A(a), B(b) {}; 

     TYPE operator() (void) { return (A + B); }; 

}; 

を可変引数リストの負担を渡すことができます。

明示的なコンストラクタは宣言時に引数リストを必要とするため、ここで変数リストを取得します。実際には...

ConcreteFunctor_add <int> addInteger (10, 10); 
addInteger(); 

...あなたはすごくいいですね。

関連する問題