2016-09-30 10 views
5

ラムダ式は未評価のコンテキスト(decltypeなど)では使用できず、最近まで定数式にすることはできませんでした。したがって、テンプレート引数でそれらを使用する方法はありませんでした。非形式のテンプレート引数でconstexprラムダを評価しました

C++では、定数式lambdaが使用できます。これは一般的にテンプレート引数でそれらを使用することはできません。しかし、具体的例えば定数式ラムダ式が評価コンテキストで使用できる非型テンプレート引数、用

template<int N> struct S { constexpr static int value = N; }; 

int main() { 
    int N = S<[]()constexpr{return 42;}()>::value; 
} 

まだかかわらず、動作しない、ラムダ式が明示的にテンプレートで禁止されているので、型または非型の引数。

私の質問は、上記の構造を許可していないという背後にある理由です。関数シグニチャのlambdaの型は問題があるかもしれないが、ここではクロージャの型自体は無関係で、(コンパイル時定数)戻り値のみが使用されることを理解できます。

私はラムダボディのすべてのステートメントがテンプレート引数式の一部になると考えています。したがって、ボディ内のステートメントが置換中に作成されていない場合、SFINAEを適用する必要があります。おそらくそれはコンパイラ開発者からの重要な仕事を必要とするでしょう。

しかし、それは実際に私の動機です。上記の構文を使用することができた場合、SFINAEは定数式だけでなく、constexpr関数で有効な他のステートメント(例えば、リテラル型宣言)でも使用できます。

コンパイラライターに与える影響に加えて、これが原因で発生する問題はありますか?標準における曖昧さ、矛盾、合併症?

+4

私はあなたがあなた自身の質問に答えだと思います。 – Barry

+0

まあ、+1 @バリーこれは実際に興味深いQ/Aです。 – skypjack

+0

@Barry私は少し質問を修正しました。私はこれが確かに唯一の主な理由であるとの確証を期待しました。おそらく、推論に言及した委員会の論文/議論への言及がありました。 – user4407569

答えて

2

ラムダは未評価のコンテキストには表示されません。ラムダが常にユニークなタイプを持っているという事実は、あらゆる種類の問題につながります。ここで

はダニエルKruglerから、 comp.lang.c++ discussionからいくつかの例です:

確かにそれはおそらく非常に可能sfinaeの例 を延長する、ラムダ 表現を可能にするためのユースケースの膨大な数が存在するでしょう(完全なコード「サンドボックス」を含む)。彼らが になったのは、この極端なsfinaeケースの拡張によるものです( はコンパイラ用のPandoraボックスを開いていました)。そして、 があなたのように他の例に問題を引き起こす可能性があります。すべてのラムダ式は、ユニークなタイプを生成するので、

template<typename T, typename U> 
void g(T, U, decltype([](T x, T y) { return x + y; }) func); 

は、役に立たないので、 パラメータで使用されるラムダの種類が異なるため

g(1, 2, [](int x, int y) { return x + y; }); 

よう 何かが実際には、動作しません。 gへの呼び出しのラムダのタイプ。

最後に、名前のマングリングの問題も発生しました。例えば。あなたは、別の翻訳単位で

template<typename T> 
void f(T, A<sizeof([](T x, T y) { return x + y; })> * = 0); 
1つの翻訳単位内

しかし

template<typename T> 
void f(T, A<sizeof([](T x, T y) { return x - y; })> * = 0); 

を持っている場合。両方の翻訳単位からf<int> をインスタンス化するものとします。これらの2つの関数は異なる シグネチャを持っているため、別々にマングル化されたテンプレート インスタンス化を生成する必要があります。それらを別々に保つ唯一の方法は、 ボディのラムダを使ってください。これは、コンパイラの作者が の文のすべての種類に対して名前のマングリング規則を思い付くことを意味します。技術的には可能ですが、これは の仕様と実装の負担の両方とみなされました。

これはすべての問題をまとめたものです。

int N = S<[]()constexpr{return 42;}()>::value; 

簡単代わりに書き込むことで解決することができます::特に書き込みのごmotiviationが与えられたことを

constexpr auto f = []() constexpr { return 42; } 
int N = S<f()>::value; 
+0

もちろんこれを投稿したので、[this Q/A](http://stackoverflow.com/q/22232164/2069064)も見つかりました。 – Barry

+0

私はテンプレート引数の問題点についてはあまりよく分かりませんが、署名の一部ではなく、SFINAEをラムダ本体に適用するのはなぜですか? – dyp

+0

@dyp SFINAEは、最初にラムダを実際に持っているのは二次的です。私はそれが重要だとは思わない。 – Barry

関連する問題