2017-04-24 2 views
3

ため、互換性のないCV-修飾子のコンパイルに失敗しました。私は2つのテンプレートメソッド

template <typename T, typename Ret, typename ...Args> 
Ret apply(T* object, Ret(T::*method)(Args...), Args&& ...args) { 
    return (object->*method)(std::forward(args)...); 
}; 

template <typename T, typename Ret, typename ...Args> 
Ret apply(T* object, Ret(T::*method)(Args...) const, Args&& ...args) { 
    return (object->*method)(std::forward(args)...); 
}; 

を持っている私の目的は、これは私のテストでこれらの引数

上のクラスのメンバー方法 Tを適用していますコード:

int main() { 
    using map_type = std::map<std::string, int>; 
    map_type map; 
    map.insert(std::make_pair("a", 1)); 
    std::cout << "Map size: " << apply(&map, &map_type::size) << std::endl; //this code work 
    apply(&map, &map_type::insert, std::make_pair("a", 1)); //failed to compile 

    return 0; 
} 

これはコンパイラエラーですssage:

test.cpp: In function ‘int main()’: 
test.cpp:61:58: error: no matching function for call to ‘apply(map_type*, <unresolved overloaded function type>, std::pair<const char*, int>)’ 
    apply(&map, &map_type::insert, std::make_pair("a", 1)); 
                 ^
test.cpp:11:5: note: candidate: template<class T, class Ret, class ... Args> Ret apply(T*, Ret (T::*)(Args ...), Args&& ...) 
Ret apply(T* object, Ret(T::*method)(Args...), Args&& ...args) { 
    ^~~~~ 
test.cpp:11:5: note: template argument deduction/substitution failed: 
test.cpp:61:58: note: couldn't deduce template parameter ‘Ret’ 
    apply(&map, &map_type::insert, std::make_pair("a", 1)); 
+0

私は[map:insert]の8つのバージョン(http://en.cppreference.com/w/cpp/container/map/insert)を見つけました。コンパイラは '&map_type :: insert'のためにどちらを使うべきですか? –

答えて

6

std::map::insertオーバーロードさ機能です。あなたが明示的にあなたが興味を持っているオーバーロードを指定しない限り、そのアドレスを取ることはできません - コンパイラが他にどのように知っていますか?

あなたの問題を解決する最も簡単な方法は、任意の関数オブジェクトを受け入れ、一般的なラムダinsertにお電話をラップapply持つことです。

template <typename F, typename ...Args> 
decltype(auto) apply(F f, Args&& ...args) { 
    return f(std::forward<Args>(args)...); 
}; 

使用法:

::apply([&](auto&&... xs) -> decltype(auto) 
{ 
    return map.insert(std::forward<decltype(xs)>(xs)...); 
}, std::make_pair("a", 1)); 

live wandbox example

追加の構文定型を避けるために、残念ながら不可能です。これは、参照、将来的に変更される可能性があります:「リフト」オペレータを導入することで、この問題を解決することを目的とした

  • N3617。 A.サットンによって

  • P0119は、引数として渡されたときに過負荷セットは基本的にあなたのための「ラッパーラムダ」を生成することを可能にすることによって、別の方法で問題を解決します。

でも、私は上記の提案でサポートされているオーバーロードされたメンバ関数かはわかりません。


あなたは、代わりに明示的には、発信者側でinterstedている過負荷を指定することで、あなたのオリジナルのソリューションを使用することができます。

::apply<map_type, std::pair<typename map_type::iterator, bool>, 
     std::pair<const char* const, int>>(
    &map, &map_type::insert<std::pair<const char* const, int>>, 
    std::make_pair("a", 1)); 

あなたはそれが非常にきれいではありません見ることができるように。それはおそらくいくつかのより良いテンプレートの引数の控除で改善することができますが、それほど多くではありません。

+0

私は* f *がクラスのメソッドである必要があります。どうすれば指定できますか? 私の悪い英語のため申し訳ありません –

+1

@PhạmVănThông:オーバーロードされた関数のアドレスを取ることができないか、*関数呼び出し式*の外でそれを参照することができないので、 '&std :: map :: insert'を渡すことはできません。あなたができることは、すべてを 'insert'に転送するラムダ/関数オブジェクトを渡すことです。マップインスタンスを取得するか、ラムダに余分なパラメータとして渡します。 –