2016-04-28 9 views
2

マップを使用して連続的なインデックスを内部的に抽象化するテンプレート化されたMatrix構造を書きました。テンプレートコールバック関数の定義を簡素化する方法は?

Matrix<TCell, TKey> m; 

は、構造を展開する機能がある、と私は、ユーザーに新たに作成された細胞を満たす関数ポインタ(initFunc)を通過させる能力を与えたいです。

void ExpandMatrix(Matrix<TCell, TKey>* matrix, 
         std::set<TKey>* keys_c, 
         std::set<TKey>* keys_r, 
         ??? /*Function pointer to callback function */ 
        ) 

今私の問題は、このユーザーが提供する機能は、セルではなく、私が使用するすべての内部カウンタの、へのポインタ、およびキーを渡される必要があること、です。テンプレートを介してTCellTKeyと定義されています。まだ正確にTCellまたはTKeyが何であるかを知られていないので、だから私は、これを使用することはできません限り私の研究が行くよう

typedef void (*initFunc)(TCell* pCell, TKey key_c, TKey key_r) 

、関数ポインタテンプレートすることはできません。

template<typename TCell, typename TKey> 
typedef void (*initFunc)(TCell* pCell, TKey key_c, TKey key_r) 

を何私は現在、ユーザーが派生すると考えられるクラスに関数をラップすることをお勧めしますが、それはユーザーにとって面倒です。より良い解決策はありませんか?

template <typename TCell, typename TKey> 
class DefaultCellInitializer 
{ 
    public: 
    virtual void Initialize(TCell* t, TKey key_c, TKey key_r) 
    { 
     return; 
    } 
}; 

template<typename TCell, typename TKey> 
void ExpandMatrix( Matrix<TCell, TKey>* matrix, 
        std::set<TKey>* keys_c, 
        std::set<TKey>* keys_r, 
        CellInitializer<TCell, TKey> initializer = DefaultCellInitializer) 

注:このメソッドの従来の使い方に対処するために何もしないデフォルト値を許可する必要があります。 C++ 11は歓迎ですが、MSVC 2012でコンパイルする必要があります。ブーストは政治のために(まだ)選択肢ではありません。

答えて

3

テンプレート関数ポインタtypedefは必要ありません。あなたは直接、関数ポインタとしてExpandMatrix()のパラメータの型を定義することができます。

template<typename TCell, typename TKey> 
void ExpandMatrix(Matrix<TCell, TKey>* matrix, 
        void (*initFunc)(TCell*, TKey, TKey) = defaultCellInitializer) {} 

defaultCellInitializer()は、あなたがそれらのテンプレートの種類を使用してstd::functionを使用することができ

template<typename TCell, typename TKey> 
void defaultCellInitializer(TCell* pCell, TKey key_c, TKey key_r) { 
    ... ... 
} 

LIVE

+0

申し訳ありませんが、これは私の心には決して来なかったtypedefの外で定義された関数ポインタを持つのに慣れています。試してみると、有望だと思われます – antipattern

2

かもしれません。これはラムダに結合することができます。

template <typename TCell, typename TKey> 
void ExpandMatrix(Matrix<TCell, TKey>* matrix, 
        std::set<TKey>* keys_c, 
        std::set<TKey>* keys_r, 
        std::function<void(TCell*, TKey, TKey)> callback 
       ); 

次にラムダ:

ExpandMatrix(/* args */, [](/* type list for arguments */) { 
    /* implementation */ 
    }); 

あなたはstd::functionにラムダをバインドするときに、あなたが必要な引数のリストで種類を提供する必要があります。

ラムダに限定されない場合は、関数ポインタも使用できます。

さらに、std::functionは、独自のテンプレート引数で置き換えることができ、標準ライブラリがアルゴリズムなどで述語を使用するのと同じ方法で使用できます(例:std::find_if)。再び

template <typename TCell, typename TKey, typename Callback> 
void ExpandMatrix(Matrix<TCell, TKey>* matrix, 
        std::set<TKey>* keys_c, 
        std::set<TKey>* keys_r, 
        Callback callback 
       ); 

callbackはラムダなどの関数ポインタ、ファンクタにバインドすることができます

+0

有望ですが、std :: functionのオーバーヘッドのために単純な関数ポインタが好きです。 @ songyuanyaoの提案が成功しない場合、私はあなたのルートに行くつもりです。 – antipattern

+0

オーバーヘッドは小さいはずですが、そこにあります。標準ライブラリが 'find_if'などの標準アルゴリズムで述語などを使用するのと同じ方法でテンプレート引数自体をテンプレートにすることができます。 – Niall

+0

私はそのステートメントであなたの提案を信用したくありませんでした。 – antipattern

関連する問題