25

T のコンストラクターについて心配する必要なく、decltype で T のインスタンスを取得するdeclval<T>()という古いトリックの代わりにすぎませんか?(*(T*)NULL)

サンプルコードは次のとおりです。

struct A {};

struct B {
    A a;
};

typedef decltype((*(B*)nullptr).a) T1;
typedef decltype(declval<B>().a) T2;

cout << "is_same: " << is_same<T1, T2>::value << endl;

T1 と T2 は同じ型であるため、1 が出力されます。

declval が代替品以上のものである場合、違いは何ですか?また、どこで役に立ちますか?

4

2 に答える 2

30

declval()評価されたコンテキストで使用される場合(つまり、odr-used)、プログラムの形式が正しくなく(20.2.4p2)、診断を発行する必要がある(1.4p1ごと)という利点があります。通常、これはstatic_assertライブラリ内のを介して実施されます。

c++/4.7/type_traits: In instantiation of '[...] std::declval() [...]':
source.cpp:3:22:   required from here
c++/4.7/type_traits:1776:7: error: static assertion failed: declval() must not be used!

declval参照型でも機能します:

using S = int &;
using T = decltype(std::declval<S>());
using U = decltype(*(S *)nullptr);  // fails

型が参照型でない場合、は左辺値を与えるdeclval右辺値型を与えます。nullptr

于 2013-02-02T00:06:30.767 に答える
8

いいえ、declval<T>()と同じではありません(*(T*)nullptr)。そしてdecltype(expr.bar)と同じではありませんdecltype((expr.bar))

前者の比較は式を比較します。後者の の使用はdecltype式を検査し、前の の使用はdecltypeの宣言された型を検査しexpr.barます。そのため、型の有用な比較を行うためにオペランドの使用を親にするdecltype必要があり、それらが異なることがわかります。

struct A {};

struct B {
    A a;
};

// E1: B().a 
// E2: declval<A>().a
// E3: (*(B*)0).a
// E4: ((B&&)(*(B*)0)).a

これら 4 つの式では、すべての式に type がありAます。E1は prvalue (C++14 では xvalue です。コンパイラによっては、C++11 モードでも xvalue として扱う可能性があります)、E2xvalue です。E3は左辺値でE4あり、再び xvalue です。

// T1: decltype((*(B*)0).a)
// T2: decltype(((*(B*)0).a))

これら 2 つの型では、最初の decltype は、式によって名前が付けられたメンバーの型を示します。メンバーのタイプAT1ですA。2 番目の decltype は式の型を生成し、式&が左辺値の場合は によって変更され&&、式が xvalue の場合は によって変更されます。式は左辺値であり、そうT2ですA&

于 2013-02-02T12:45:30.163 に答える