キャプチャレスラムダは標準で空であることが保証されていますか?


12

テンプレート関数で他のラムダから空の(キャプチャレス)ラムダを識別する方法を探しています。現在C ++ 17を使用していますが、C ++ 20の回答にも興味があります。

私のコードは次のようになります:

template<typename T>
auto func(T lambda) {
    // The aguments of the lambdas are unknown

    if constexpr (/* is captureless */) {
        // do stuff
    }
}

C ++標準(17または20)で、関数ポインターに変換可能なキャプチャレスラムダでもstd::is_empty歩留まりがtrueになることが保証されていますか?

例としてこのコードを見てください:

auto a = []{}; // captureless
auto b = [c = 'z']{}; // has captures

static_assert(sizeof(a) == sizeof(b)); // Both are the same size
static_assert(!std::is_empty_v<decltype(b)>); // It has a `c` member
static_assert(std::is_empty_v<decltype(a)>); // Passes. It is guaranteed?

実例


2
テンプレート以外のラムダのみに関心がある場合は、SFINAEを使用して、関数ポインター(+lambda)への変換が整形式かどうかを確認できます。
HolyBlackCat

@HolyBlackCat私はそれについて考えましたが、私の知る限り、MSVCは変換演算子をオーバーロードしているのでそれを許可しません。
ギヨームラシコット

@GuillaumeRacicot MSは、利用可能なすべての呼び出し規約に対して個別の変換演算子を公開します。1つを選択して、ラムダを同等の関数ポインターに変換し、それが成功するか失敗するかを確認してください。
レミールボー

回答:


13

いいえ、実際には、規格ではラムダが宣言と一致しないサイズを持つことを明示的に許可しています。 [expr.prim.lambda.closure] / 2状態

クロージャタイプは、対応するラムダ式を含む最小のブロックスコープ、クラススコープ、または名前空間スコープで宣言されます。[注:これは、クロージャタイプ([basic.lookup.argdep])に関連付けられている名前空間とクラスのセットを決定します。ラムダ宣言子のパラメーター型は、これらの関連する名前空間とクラスには影響しません。—終了注]クロージャタイプは集約タイプではありません。実装では、以下の説明とは異なる方法でクロージャタイプを定義する場合があります。ただし、これにより、プログラムの監視可能な動作が変更されない限り変更されません。

  • クロージャタイプのサイズや配置

  • クロージャタイプが簡単にコピーできるか([class.prop])、または(2.3​​)

  • クロージャタイプが標準レイアウトクラス([class.prop])かどうか。

実装では、右辺値参照型のメンバーをクロージャー型に追加しないでください。

重点鉱山

したがって、これにより、実装でラムダにキャプチャがなくてもメンバーを与えることができます。私はこれまでどんな実装もそうだとは思わないが、彼らは合法的にそうすることを許可されている。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.