2012-12-10 17 views
6

この質問は以前に尋ねられたことは知っていますが、かなり経験豊富なコーダーではありますが、私は答えを理解していないため、明確化。 「返信」リンクなどはありません。その上、これらの質問はかなり古いものでした。だから私は質問を新たに求めている。C++でstd :: functionのシグニチャをオーバーロードする方法

クラスがあり、+ =演算子がオーバーロードされています。私は1つの過負荷が裸関数ポインタをしたい、と他のSTD ::機能を取るために:

void operator+=(void (*handler)()); 
void operator+=(function<void (void *, T)> handler); 

使用方法:コンパイラが判断できないため

MyClass a; 
a += [](){ DoSomething(); }; 
a += [](void *x, T y){ DoSomething(); }; 

残念ながら、コードはコンパイルされません。 2番目のオーバーロードは最初の+ =コールには不適切であることを示します。

この問題を解決するには、演算子+ =メンバ関数をどのように定義すればよいですか?演算子の使用方法を変更する(たとえば、明示的なキャストを使用するなど)必要はありません。私は彼らが上記のように働くことを望みます。また

、同様に、以下の過負荷を持っていると便利だろう:

void operator+=(function<void()> handler); 

しかし、再び、私は機能<>テンプレートの署名に基づいてオーバーロードすることはできません。

さらなる例については、このスレッドを参照してください:Isn't the template argument (the signature) of std::function part of its type? (私はそのスレッドで述べたさまざまなソリューションを導入しようとした、およびそれらのどれもをコンパイルしないだろう)

私は数に長年にわたってプログラミングをしてきました私のC++スキルは少し錆びています。

+0

**大きな問題は:__what与えられた関数ポインタまたは 'std :: function'オブジェクトをあなたのオーバーロード' operator + = 'で実行しようとしていますか?__ – zaufi

+0

@zaufi:それは関連していますが、大丈夫です。イベントハンドラ関数のstd :: vectorに追加します。私は本質的にC++で.NETイベントを実装しています。なぜなら、イベントやプロパティーはクローズのようなものであり、現代のプログラミング言語には絶対不可欠な機能だからです。 –

+0

だから、あなたは 'std :: vector'をexaclyと' std :: function'でインスタンス化しなければなりません(私は 'void()')シグニチャを...そうですか? – zaufi

答えて

3

がg ++ 4.7.2でうまく動作します。そのコンストラクタはすべてを引数として受け取ります。その引数に適切なoperator()がない場合、コンストラクターのインスタンス化中にエラーが生成されます。

残念なことに、オーバーロードの解決プロセスでは、テンプレート関数をインスタンス化する必要がないため、コンパイラはすべてをstd::function型に変換できると考えています。

+0

ありがとう、私はちょうど問題なく私のクラスにそれを得ることができた。私はTを関数<>にキャストしようとしたときに、少し毛深いものでした。私はそれを最初にvoid(*)()にキャストしなければならないようだ。乾杯。 –

+0

私が持っていた主な問題は、私がenable_ifについて聞いたことがなく、それを理解していないということです。私はそれが(類似の質問への答えを見ることから)助けになるかもしれないことを漠然と知っていたが、それがどのように使われたのか分からなかった。私はまだそれがどのように動作するのか分かりません。 –

+0

'enable_if'に関するいくつかの情報は、[here](http://www.boost.org/doc/libs/1_52_0/libs/utility/enable_if.html)および[here](http://en.cppreference .com/w/cpp/types/enable_if)。 – hpsMouse

0

あなたがstd::vector<std::function<void()>>を持っている場合は、過負荷の束を持つ必要はありません。最も簡単な方法は、テンプレートoperator+=を定義し、std::enable_ifで可能な「ガード」を呼び出し可能オブジェクトまたは関数ポインタに対してのみオンにすることです。したがって、ラムダまたは生ポインタを渡すと、assign(push_back/emplace_back)で自動的に変換されます。 std::functionを渡すと、期待どおりに割り当てられます。問題はtemplate <class F> function(F);として宣言されているstd::functionのコンストラクタによって引き起こされ

#include <functional> 
#include <iostream> 

template <typename T> 
typename std::enable_if<std::is_convertible<T, void(*)()>::value>::type 
foo(T&&) 
{ 
    std::cout << "foo(void(*)())" << std::endl; 
} 

void foo(std::function<void(void*,int)>) 
{ 
    std::cout << "foo(std::function<void(void*,int)>)" << std::endl; 
} 

int main() 
{ 
    foo([]{}); 
    foo([](void*,int){}); 
} 

:コードに続いて

+0

あなたはポイントを見逃しています。私は "[](){}" lambdasと "[](void *、T){}" lambdasをベクターに追加したいと思います。私はそれらを共通のコンテナクラスにラップし、それを私のベクトルに追加します。私が別のラムダ署名を必要としないことを私に納得させようとすると、あなたの時間と鉱山の無駄です。 –

関連する問題