3

私は次のコードを見ています:

#include <iostream>

void f()
{
    std::cout << "Called ::f()" << std::endl;
}

struct S
{
    void f()
    {
        std::cout << "Called S::f()" << std::endl;
    }

    void oops()
    {
        [this](){ f(); }(); // calls the wrong function
    }
};

int main()
{
    S().oops();
    return 0;
}

http://ideone.com/w7nyb

VS2010は呼び出します::f()が、GCCとVS2012は呼び出しますS::f()。私には、VS2012は正しいようです。

標準に従ってどの関数を呼び出す必要がありますか?

4

1 に答える 1

5

S::f()呼び出す必要があります。C++11§5.1.2/7の状態:

ラムダ式複合ステートメントは、関数呼び出し演算子の関数本体を生成しますが、名前検索の目的で、非静的クラスメンバーを参照するidthis式のタイプと値を決定し、クラスメンバーアクセス式に変換しますを使用すると、複合ステートメントラムダ式のコンテキストで考慮されます。(*this)

ここで重要なのは、「名前検索の目的で、複合ステートメントラムダ式のコンテキストで考慮される」ということです。ラムダブロックにはローカルで宣言されていないためf、の本体から直接参照された場合と同じようにルックアップされoopsます。したがって、メンバー関数が見つかります。


Visual C ++とgccの最近のバージョンはどちらも正しい動作をしていることに注意してください(Visual C ++2012とgcc4.7.2を含む)。ラムダ仕様が2009年の後半にオーバーホールされたため、古いバージョンでは誤った動作が見られる場合があります(n2927:C ++ 0x Lambdasの新しい表現[PDF]を参照)。C ++ 11が完成する前は、仕様は動くターゲットであり、古いコンパイラは仕様のさまざまなリビジョンを実装する可能性が高いことを忘れないでください。現在でも、多くの実装者が最終仕様に追いつくために取り組んでいます。

于 2012-10-15T23:49:45.100 に答える