_std::declval
_ は、型を判別する目的で式を作成するために使用されるコンパイル時ユーティリティです。これは次のように定義されます。
_template< class T >
typename std::add_rvalue_reference<T>::type declval() noexcept;
_
代わりにこれは簡単ではないでしょうか?
_template< class T >
T declval() noexcept;
_
参照戻り値の型の利点は何ですか?そして、それはdeclref
と呼ばれるべきではありませんか?
私が見つけた最も初期の歴史的な例は n2958 で、これは関数value()
を呼び出しますが、すでに常に参照を返します。
decltype
のオペランドは、アクセス可能なデストラクタを持っている必要はありません。つまり、完全な式として意味的にチェックされないことに注意してください。
_template< typename t >
t declprval() noexcept;
class c { ~ c (); };
decltype ( declprval< c >() ) * p = nullptr; // OK
_
「decltype
のオブジェクトタイプのprvalueを返す関数に一時的なものは導入されません」ルールは、関数呼び出し自体がdecltype
のオペランド、またはdecltype
のオペランドであるコンマ演算子の右オペランドのいずれかである場合にのみ適用されます(§5.2.2[expr .call]/p11)、これは、OPでdeclprval
が指定されていることを意味します。
template< typename t >
t declprval() noexcept;
class c { ~ c (); };
int f(c &&);
decltype(f(declprval<c>())) i; // error: inaccessible destructor
コンパイルされません。より一般的には、T
を返すことで、不完全な型、プライベートデストラクタを使用した型などでのdeclval
のほとんどの重要な使用を防ぐことができます。
class D;
int f(D &&);
decltype(f(declprval<D>())) i2; // doesn't compile. D must be a complete type
xvaluesはdecltype
を使用する場合を除いて、prvaluesとほとんど区別がつかず、通常はdecltype
の戻り値に直接declval
を使用しないため、これを行うことにはほとんどメリットがありません。タイプはすでにわかっています。
配列を値で返すことはできないため、値で配列を返す関数の宣言だけでも無効なコードです。
ただし、参照によって配列を返すことができます。
decltype()
の目的は、タイプT
の有効な値として機能する式を作成し、T
sを期待する式にT
として配置することです。 。問題は、C++では、タイプT
がコピー不可能であるか、デフォルトで構築できない可能性があることです。したがって、その目的で_T{}
_を使用することは機能しません。
decltype()
が行うことは、右辺値参照をT
に返すことです。右辺値参照はすべてのタイプT
に対して有効である必要があるため、T
の右辺値参照から有効なT
があることが保証され、右辺値を持つことができることが保証されます任意のタイプへの参照T
。それがトリックです。
decltype()
を "T
"型の有効な式を教えてください。もちろん、その使用法は、過負荷の解決、タイプの決定などを目的としています。その目的は有効な式(構文上の意味で)を返すことであり、値を返すことではないためです。これは、std::declval()
がまったく定義されておらず、宣言されているだけであるという事実に反映されています。
それが定義された場合、最初の問題が再び発生します(任意の型T
の値を作成する必要があり、それは不可能です)。