7

GCC 4.8 の最近のビルドでは、ヘッダー ファイルに次のコードが表示されます。

auto L = [](){};

struct S
{
    decltype(L) m;
};

次の警告:

test.hpp:3:8: warning: 'S' has a field 'S::m' whose type uses the anonymous namespace [enabled by default]
 struct S
        ^

コンパイラが匿名名前空間を使用するラムダの型を考慮するのはなぜですか? ラムダをグローバルにしました。匿名の名前空間はどこにも使用しませんでした。

UPDATE :次のように、ラムダを明示的な名前空間に配置しても、コンパイルは同じ警告を出します:

namespace N
{
    auto L = [](){};
}

struct S
{
    decltype(N::L) m;
};

UPDATE 2 : 実際、クラススコープのラムダにも同じ問題があるようです:

class N
{
    static constexpr auto L = [](){};
};

struct S
{
    decltype(N::L) m;
};
4

4 に答える 4

7

§5.1.2/3:

ラムダ式の型(クロージャオブジェクトの型でもあります)は、一意の名前のない非ユニオンクラス型(クロージャ型と呼ばれます)であり、そのプロパティについては以下で説明します。このクラスタイプは集合体ではありません(8.5.1)。クロージャタイプは、対応するラムダ式を含む最小のブロックスコープ、クラススコープ、または名前空間スコープで宣言されます。

したがって、匿名名前空間内のコードでラムダ式を定義しているのでない限り、ラムダの型も匿名名前空間に含めるべきではありません。

于 2012-07-18T04:37:49.453 に答える
4

私が何かを見逃していない限り、これらのどれも匿名の名前空間にあるべきではありませんが、少なくともGCCとMSVCの両方がそれらをそこに置いているようです。

§5.1.2 [expr.prim.lambda] p3

[...]クロージャタイプは、対応するラムダ式を含む最小のブロックスコープ、クラススコープ、または名前空間スコープで宣言されます。[...]

少なくともClangはそれを正しく理解しているようで、クロージャータイプは本来あるべき場所にあります。

(ラムダ型が存在する名前空間をテストするには、ラムダをある種の警告/エラー生成コードに含めるだけです。コンパイラーは、警告/エラーとともにその型を吐き出す必要があります。)

于 2012-07-18T04:41:20.520 に答える
1

GCC の警告は少しわかりにくいかもしれませんが、その意図は確かに正しいです。ラムダの型には名前がなく、プログラム全体で一意です。一方、クラスが名前のない名前空間に配置されていない場合(説明を考えると、そうではないと思います)、クラスは、それを含めるすべての翻訳単位で同じタイプです。同じクラスは同じメンバーを持つ必要があり、異なる翻訳単位で異なるメンバーを持つべきではないため、これは違反です (未定義の動作につながります)。

少なくとも悪いのはLexternヘッダーを複数の翻訳単位に含めると、「L の複数の定義」リンカー エラーが発生することです。

于 2012-07-18T22:22:28.277 に答える
0

この場合、仕様を読んでいないので、考えてみてください...でも、テストしてもらえますか?

あなたのラムダは取るに足らないものであり、ステートレスラムダになる可能性があります。あなたのようなステートレスラムダは、コンパイラによって単純なC関数になる可能性があります。この関数を匿名の名前空間に配置して、単一のコンパイル単位にのみ存在するようにする規則がある場合があります。

したがって、変数を参照するように非ステートレスにして、この匿名の名前空間にまだ存在するかどうかを確認することをお勧めします。

于 2012-07-18T04:43:31.987 に答える