5

この質問は私の最近の質問の続きです:
What is this compiler error when using a lambda as a template parameter?
λを返すラムダは、戻り値の型を間違って推定しますか?

2014年11月11日:マイクロソフトは、このバグの修正は、Visual Cの++の次のメジャーリリースで表示されるはずですと言って対応してきました。


このコードは、VS2012(更新2)を使用してコンパイルに失敗します。

int main(int argc, char* argv[]) 
{ 
    auto f = []() 
    { 
     int n = 0; 
     auto r = [=]{ return n; }; 
     return r; 
    }; 
    return 0; 
} 

これは私が取得コンパイラエラーです:

1> main.cpp 
1>C:\test\main.cpp(7): error C2440: 'return' : cannot convert from 'main::<lambda_c5d1d707b91a1ddedc06eb080503550c>::()::<lambda_ac357c309731f4971c3269160ed9c24b>' to 'int (__cdecl *)(void)' 
1>   No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 

  • 問題はありますか C++ 11仕様のコードを使用していますか?
  • VS2012の部分C++ 11サポートで定義されているコードに問題はありますか?
  • これはVS2012 C++コンパイラのバグですか?

  • 誰かがラムダは、関数ポインタに暗黙的にキャスト可能でなければならないかについて語っC++ 11の仕様に場所に私を指すもらえますか?では、なぜラムダfの推測された戻り値の型が関数であることを表示されない内側のラムダrない
  • ある - 空のキャプチャ句を持つもの -
    • 私はこれが唯一のステートレスラムダのためであることを思い出しますポインタ、つまりint (__cdecl *)(void)
+0

するのは、それが原因で貧困層のだとしましょう実装:-) –

+1

@CaptainObvlious OK - しかし、関数ポインタへのキャストは明示的に禁止されています*ステートフル* lambdas、正しい? –

+0

[私の以前のコメントにどういう_ _ "not" _が入っているのかわかりません;)] 5.1.2/6によれば、取り込みがなければ変換は必要です。標準では、ステートフルなラムダには変換が含まれないように_explicitly_禁止しています。ステートフルなラムダであっても、実装に自由に変換を含めることはできません。 –

答えて

2

GCC 4.7.2は、それが病気に形成されています。このコードをコンパイルしますが。 fを初期化するラムダ式は、戻り値の型を推測するには複雑すぎます。

:確かに、5.1.2/4ラムダ式はトレーリング戻り値型が含まれていない場合は、トレーリング戻り値型は、次の型を表すかのように、それは

語ります - 化合物文の形式である場合

{ attribute-specifier-seq[opt] return expression ; } 

左辺ツー右辺値変換(4.1)、アレイへのポインタ変換(4.2)の後返さ式の型、及び機能・ツー・ポインタ変換(4.3)。

- それ以外の場合は無効です。

したがって、この例では戻り値の型はvoidですが、ラムダは、何か他のものを返しています。コードはコンパイルすべきではありません。

私は、Visual Studioのメッセージが誤解を招くことに同意します。

更新:この質問に

だから、「あなたがステートフルラムダを返すラムダを定義することはできません、C++ 11では、」言うことが正しいのでしょうか?以下のC++ 11クォートあたりとして

号ラムダの本体はreturn expression;とちょうど単一の行が含まれていない限り、ラムダによって返されるタイプはvoidあります。したがって、リターン式でステートフルなラムダを作成すると、これは問題ありません。例えば、以下のコードは、GCC 4.7.2でコンパイルし、クラン3.2およびインテルコンパイラー13.1.0:(それが原因前述のバグにVS2012でコンパイルされません。)

#include <iostream> 

int main() { 
    int n = 5; 
    auto f = [=] { 
     return [=]{ return n; }; // creates a stateful lambda and returns it in a single line 
    }; 
    std::cout << f()() << std::endl; 
    return 0; 
} 
+0

"したがって、この例では戻り値の型は' void'です。 ... "コンパイラが言っていることとは一致しません。コンパイラは戻り値の型が 'int(__cdecl *)(void)'であると言っています。さらに、 'auto r = ...;行のラムダ型から' int(__cdecl *)(void) 'である' f'の戻り型に変換することはできません。 。私が間違っているなら私を訂正してください。私は混乱しています。 :) –

+0

@TimothyShields:GCCはC++ 11としてコードを受け入れるのは間違っています(C++ 14 CDでは正しいですが)。 Visual Studioは、コードを受け入れないのは間違っていますが、ステートフルなラムダを関数ポインタに変換してはいけません。 –

+0

この最近の私の質問にあなたの考えを教えてください。私はそこにある答えがあなたの洞察に基づいて正しくないかもしれないと思います。 http://stackoverflow.com/questions/16661981/what-is-this-compiler-error-when-using-a-lambda-as-a-template-parameter –

関連する問題