2015-10-12 20 views
9

私の質問は、静的メンバー初期化子のラムダスコープについてです。以下の試験を検討:4.8から出発静的メンバーの初期化子のラムダスコープ

#include <functional> 
#include <iostream> 

struct S { 
    static const std::function<void(void)> s_func; 
}; 

const std::function<void(void)> S::s_func = []() { 
    std::cout << "Hello from " << __PRETTY_FUNCTION__ << std::endl; 
}; 

int main(void) { 
    S::s_func(); 
    return 0; 
} 

GCCはSの範囲にラムダを定義するので、プログラムは、このようなものを出力:

Hello from S::<lambda()> 

(GCC-4.8.2は異なる定義を有します__FUNCTION__ &コマクロため、それにもかかわらず、ラムダは依然としてS内で定義される)

一方GCC-4.7は、グローバルスコープにラムダを定義し、そのプログラム出力

Hello from <lambda()> 

おそらく、より新しいgccが標準に準拠しています。しかし、標準が実際にこのアスペクトを指定しているのか、それとも実装に依存しているのかを尋ねたいと思います。

更新は:@ user5434961として全て__FUNCTION__ -alikeマクロは実装に依存していることを示唆し、それは、標準に準拠したテストでそれらを避ける方が良いでしょう。そこでここでは、コンパイラはS範囲内で、そのようなラムダを定義し、それ以外の場合は、コンパイルを中断した場合にコンパイルすることができます例です。

#include <functional> 
#include <iostream> 

struct S { 
    static const std::function<void(void)> s_func; 
private: 
    static const int s_field; 
}; 

const std::function<void(void)> S::s_func = []() { 
    std::cout << "Hello from S::s_func. S::s_field = " << S::s_field << std::endl; 
}; 

const int S::s_field = 1; 

int main(void) { 
    S::s_func(); 
    return 0; 
} 
+0

私はあなたが 'にSを変更する必要があります:: s_field'を更新例ではちょうど' s_field'に思いますか?さもなければ、私はそれが常にスコープが何であれコンパイルすると思う。 'S :: s_field'がプライベートであるため、コードは、はい、はい確かにGCC-4.7に – Lingxi

+0

まあ、それはグローバルスコープからアクセスすることはできません。私は私物を見落とした。 – user3159253

+0

をコンパイルを破るないので – Lingxi

答えて

7

この問題は、以前に提起されてきたが、私は、関連するバグレポートを見つけることができません。おそらく提出されたMSVCバグレポートのbroken linkがあります(まだ2015年に修正されていません:rise4funでテストできます)。しかし、GCCの4.7から4.8の間のどこかに修正されています。バグとしてこれをバックアップするために使用される関連standardeseである:

[C++ 11、9.4.2/2] staticデータメンバのデのfi nitionにおける初期の発現は、そのクラスの範囲内にあります。

[C++ 11,5.1.2/2]ラムダ式の評価結果は、一時的に(12.2)prvalueになります。この一時的なものをクロージャーオブジェクトといいます。ラムダ式は未評価のオペランドには出現してはならない(5節)。

[C++ 11、5.1.2/3](また、クロージャオブジェクトの タイプである)ラムダ式の型は、固有、無名非組合クラス型 ある - クロージャと呼ばれますtype - プロパティは以下に説明されています。この クラスタイプは集約ではありません(8.5.1)。クロージャの型は、 のブロックスコープ、クラススコープ、またはネームスペーススコープの中で、 に対応するラムダ式が含まれていると宣言されています。

以前

Why lambda in static initializer can't access private members of class in VC++2013?

C++11 lambdas can access my private members. Why?

Why is it not possible to use private method in a lambda?

4

私はそれは、クラスのスコープ内にある必要がありますね。cppreference(強調鉱山)から引用:

ラムダ式は、ADLのために宣言されている閉鎖型として知られているユニークな名前非組合非凝集型の名前prvalue一時オブジェクト 、 を(構築しますラムダ 発現を含む最小ブロック スコープ、クラススコープ、または名前空間スコープ内)S::s_funcのアウトオブライン定義で

、あなたはSの範囲にS::が発生した時間を入力します。したがって、ラムダ式はクラススコープSに含まれています。クローザータイプがSのメンバーであるため、Sのプライベートメンバーへのアクセスが許可されます。

+0

あなたと@ user5434961の両方にお役に立てれば幸いです。私はあなたの答えより少し早かったので、彼の答えを受け入れたとマークしました。 – user3159253

+0

@ user3159253あなたは大歓迎です:) user5434961の回答は、標準の文書を引用するよりも優れています。 – Lingxi

関連する問題