2016-05-14 20 views
4

私は非常に奇妙な問題があります。物事をシンプルに保つために、私はcstdioをからputcharを取り、putcharに一致するように同一の機能を作成した事を試すために、引数テンプレート関数としてラムダ

template<typename Func> 
void foo(Func a, Func b) 
{ 
    std::cout << "good"; 
} 

と同じ宣言で2つの機能を取る機能を持つようにしたいと言うことができます。今

int myPutcharFunc(int) 
{ 
    return 0; 
} 

int main() 
{ 
    auto myPutcharLambda = [](int) -> int 
    { 
     return 0; 
    }; 

    foo(putchar, myPutcharFunc); // okay 
    foo(putchar, myPutcharLambda); //deduced conflicting types for parameter 'Func' ('int (__attribute__((__cdecl__)) *)(int)' and 'main()::<lambda(int)>') 
} 

、ラムダは、(キーは、私はラムダ・キャプチャーを使用したいです)をコンパイルする必要はありません。

プログラマがマシンよりも賢いので、テンプレートの特殊化を追加できますか? :)

template<typename Func> 
void foo(Func a, Func b) 
{ 
    std::cout << "good"; 
} 

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

いいえ、同じエラー - なぜですか? しかし、私はテンプレートの特殊化をコメントアウト何らかの理由で、用:

//template<> 
void foo(int(*)(int), int(*)(int)) 
{ 
    std::cout << "good"; 
} 

コードがコンパイルされます。私は明らかに関数の引数のすべてのセットのためにfooをオーバーロードしたくない - それはどのようなテンプレートであるか。すべてのステップは、msvC++とg ++の両方でテストされました。私は間違って何をしていますか?あなたは(補正のためのCOMMENTを参照)、テンプレートの種類を推定する際

template<typename FuncA, typename FuncB> 
void foo(FuncA a, FuncB b) 

タイプが減衰していないそれらを得るために、2つの異なるテンプレートパラメータを持っている必要がありますので、

答えて

2

すべてのラムダは、異なるタイプです。したがって、ラムダはラムダのままであり、関数ポインタには崩壊しません。文字列リテラルがconst char *の代わりにchar[N]として推定されるのと同じ理由があります。

特殊化を使用した2番目の例では、ラムダが関数ポインタではないため、特殊化は使用しません。ラムダを関数ポインタにキャストして動作させることができます:https://godbolt.org/g/ISgPciトリックここで言うことができるのは+ my_lambdaです。+はポインタのために定義されているため、キャプチャしていないラムダを関数ポインタにする必要があります。

+0

* "テンプレートの種類を推定する際の種類は減衰していない" *もちろん彼らはありません。 * "同じ理由は、文字列リテラルがconst char *" *の代わりにchar [N]として推論されるのと同じですが、生の文字列リテラルはconst char * –

+0

@PiotrSkotnickiとして引き合いに出されます。私は他のいくつかの援助でそれについて読んでいただけです。 – xaxxon

+0

関数パラメータが参照型の場合 –

2

2つの可能性があります。

:ちょうどラムダの前に +を置く:

単項 +は、ポインタとして、整数のような値を想定しているため作品
foo(putchar, +myPutcharLambda); 

。したがって、ラムダは関数ポインタに変換されます。

最終的には、関数ポインタに変換しようとしているにもかかわらず、(捕捉されていない)ラムダは関数ポインタと同じ型を持ちません。

コンパイラは、同じタイプの2つのオブジェクトを作成できるコンバージョンをどのように知っていると思いますか?

は:?:converting one type to another in some circumstances、いくつかの変換をしても構わないと思っていることを利用し、別のオプションがあります。

template<typename Func1, typename Func2> 
void foo2(Func1 a, Func2 b) 
{ 
    using common_type = decltype(true?a:b); // or 'false', it doesn't matter 
    foo<common_type>(a,b); 
} 
+1

オプション1は特にいたずらです。 :) – erip

1

ラムダは、関数ポインタに減衰することができなくテンプレート関数が一致した場合には、それは本当の機能のためにあなたがいるため、暗黙的な変換を見つけますよう、独自の型を持ちます。

テンプレートにマッチする場合は、必要なタイプのfooを明瞭にインスタンス化するか、ラムダを関数ポインタに変換する必要があります。

foo<decltype(putchar)>(putchar, myPutcharLambda); 

または

foo(putchar, +myPutcharLambda); 
関連する問題