4

大きなクラスのプライベートデータ内のメンバークラスの関数ポインタであるパラメータをとるテンプレートクラスの関数を記述しようとしています。そのメンバーを呼び出すと、そのクラスを小さなクラスで呼び出します。実証する(右の混乱?)、私はここに非稼働の例があります。テンプレートクラスのテンプレート変数関数はコンパイルされません

#include <vector> 
#include <iostream> 

using namespace std; 

template <typename T, typename C> 
struct MyClass { 

    template <typename F, typename... A> 
    auto call_me(F func, A... args) { // pass in the function we want to call 
     return (mContainer.*func) (args...); // call the function supplied by 
     // the parameter on the private member data 
    } 

    C mContainer; // this will be private in my actual code 

}; 


int main() { 
    MyClass<int, std::vector<int> > test;; 

    cout << test.call_me(&std::vector<int>::size) << endl; // works 
    test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); // doesn't work 

    return 0; 
} 

を、これは私の実際のコードが、私は何をしようとしているの小さな例ではないことに注意してください。ご覧のとおり、私はsizeのメンバー関数を 'Private'(私はデモのためにここに公開しています)vectorクラス内のMyClassクラスのメンバー関数に呼び出そうとしています。私は解凍するようにコンパイラーにはパラメータを持っていないが、私は(解凍するためのパラメータを持っている)の挿入機能を実行しようとする場合、コンパイラは私のエラーを与えるたび、この唯一の作品:

.\template.cpp: In function 'int main()': 
.\template.cpp:24:71: error: no matching function for call to 'MyClass<int, std::vector<int> >::call_me(<unresolved overloaded function type>, std::vector<int>::iterator, int)' 
    test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); 
                    ^
.\template.cpp:10:10: note: candidate: template<class F, class ... A> auto MyClass<T, C>::call_me(F, A ...) [with F = F; A = {A ...}; T = int; C = std::vector<int>] 
    auto call_me(F func, A... args) { // pass in the function we want to call 
      ^~~~~~~ 
.\template.cpp:10:10: note: template argument deduction/substitution failed: 
.\template.cpp:24:71: note: couldn't deduce template parameter 'F' 
    test.call_me(&std::vector<int>::insert, test.mContainer.begin(), 4); 

これが同じですエラー私は実際の生産コードを取得しています。パラメータを指定しないで変数を指定して関数を呼び出して作業を展開しますが、それ以上のものを与えると同じエラーメッセージが表示されます。これはVariadicテンプレートを使用する私の最初の実際の試みです。だから、どんな勧告と助けにも感謝します。

答えて

6

ここでの問題は、insertがオーバーロードされた機能であることです。コンパイラは、テンプレート引数の控除で必要なオーバーロードを知る方法がないため、試して解決しようとしていません。タイプを与えるために使用するオーバーロードのタイプに関数をキャストする必要があります。つまり、別のオプションは、少し機能を変更し、あなたが完了欲しいものを表現するラムダを取ることであろう

static_cast<return_type(class_name::*)(function_parameters)>(&class_name::function_name) 

で一般的に

using insert_func_t = std::vector<int>::iterator(std::vector<int>::*)(std::vector<int>::const_iterator, const int&); 
test.call_me(static_cast<insert_func_t>(&std::vector<int>::insert), test.mContainer.begin(), 4); 

ようになります。これは、コンパイラが正しい関数のエントリ・ポイント・アドレスを選択することはできませんので、基本的には、未解決のオーバーロードされた関数のアドレスを取ることができない

template <typename T, typename C> 
struct MyClass { 

    template <typename F, typename... A> 
    auto call_me(F func, A... args) { // pass in the function we want to call 
     return func(mContainer, args...); // call the function supplied by 
     // the parameter on the private member data 
    } 

    C mContainer; // this will be private in my actual code 
}; 

int main() { 
    MyClass<int, std::vector<int> > test;; 

    test.call_me([](auto& container, auto... args){ container.insert(args...); }, test.mContainer.begin(), 4); 

    return 0; 
} 
+0

は、どのように私はそれをやって行くのでしょうか?グーグルでは、static_castを使用するようになりますが、これはうまくいきません。 'test.call_me(static_cast :: iterator、int)>(&std :: vector :: insert)、test.mContainer.begin()、4);'を呼び出します。それを行う他の方法はありますか? – Aryan

+0

@Aryan私はちょうど答えにキャストを追加 – NathanOliver

+0

ありがとう、それは働いた。もっと美しい方法がありますか?または、キーストロークの少ないもの? – Aryan

0

ようになります。通常の関数呼び出しでは、コンパイラはオーバーロードされた関数を解決しますが、あなたやstd :: bind()のようなテンプレートでは機能しません。なぜなら、パラメータはテンプレート関数を呼び出すためであり、

using ftype = std::vector<int>::iterator(std::vector<int>::*) 
     (std::vector<int>::const_iterator, const std::vector<int>::value_type&); 
    test.call_me((ftype)(&std::vector<int>::insert), test.mContainer.begin(), 4); // works 
0

それはこの種のものをやったときに関数オブジェクトに対処する方が簡単です:

は、手動でこのような過負荷を解決することができます。メソッドのオーバーロードの問題をコンパイラにオフロードします。

ラムダは、(彼らは関数オブジェクトです)仕事:

#include <vector> 
#include <iostream> 

template <typename T, typename C> 
struct MyClass { 

    template <typename F, typename... A> 
    auto call_me(F func, A&&... args) -> decltype(auto) 
    { // pass in the function we want to call 
     return func(mContainer, std::forward<A>(args)...); // call the function supplied by 
     // the parameter on the private member data 
    } 

    C mContainer; // this will be private in my actual code 

}; 
/* 
* It's often easier to deal in function objects 
*/ 
struct insert 
{ 
    template<class Container, class...Args> 
    decltype(auto) operator()(Container& cont, Args&&...args) const 
    { 
     return cont.insert(std::forward<Args>(args)...); 
    } 
}; 

struct size 
{ 
    template<class Container, class...Args> 
    decltype(auto) operator()(Container& cont) const 
    { 
     return cont.size(); 
    } 
}; 

int main() { 
    MyClass<int, std::vector<int> > test;; 

    std::cout << test.call_me(size()) << std::endl; // works 
    test.call_me(insert(), test.mContainer.begin(), 4); // doesn't work 

    // or lambdas 
    auto insert2 = [](auto& container, auto&&...args) -> decltype(auto) 
    { 
     return container.insert(std::forward<decltype(args)>(args)...); 
    }; 
    test.call_me(insert2, test.mContainer.begin(), 5); 


    return 0; 
} 
関連する問題