declval <T>()与(*(T*)nullptr)相同吗?

wal*_*rii 23 c++ decltype c++11

declval<T>()只为老把戏的替代品(*(T*)NULL),以获得T的实例在decltype,而无需担心T的构造函数?

以下是一些示例代码:

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;
Run Code Online (Sandbox Code Playgroud)

打印1,因为T1和T2是相同的类型.

如果declval不仅仅是替代品,那么差异是什么?它在哪里有用?

eca*_*mur 28

declval()具有以下优点:如果在评估的上下文中使用(即,使用了odr),则程序形成不良(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!
Run Code Online (Sandbox Code Playgroud)

declval 也适用于引用类型:

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

如果类型不是引用类型,declval则给出一个rvalue类型,其中nullptr给出一个左值.

  • @walrii这是正确的,除了在运行时不保证段错误. (3认同)
  • 只是为了确保我理解您的第一点:在decltype之外使用declval会导致编译错误,而在同一位置使用(\ *(T \ *)NULL)不会在编译时引起抱怨,而在运行时会引起segfault。十进制类型显然更好。 (2认同)
  • 请注意,这并不总是严格意义上的优势。例如,如果出于某种原因您需要了解类成员的地址偏移量,则[casting-a-literal技巧将使您无需构造实际的类对象即可确定此偏移量](http://stackoverflow.com/ q / 36165639/1858225),但`declval`不会。 (2认同)
  • 是否有比“错误:静态声明失败:绝对不能使用declval()!”更混乱的消息?普通程序员会抱怨“如果不使用它,为什么会存在”。它们可能表示“绝对不能使用”,或者应该完全改变IMO的信息。 (2认同)

Joh*_*itb 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
Run Code Online (Sandbox Code Playgroud)

在这4个表达式中,所有表达式都有类型A.E1是一个prvalue(在C++ 14中它是一个xvalue.有些编译器可能会将它视为xvalue,即使在它的C++ 11模式下),E2也是一个xvalue.E3是一个左值,又E4是一个x值.

// T1: decltype((*(B*)0).a)
// T2: decltype(((*(B*)0).a))
Run Code Online (Sandbox Code Playgroud)

在这两种类型中,第一个decltype给出了由表达式命名的成员的类型.所述构件具有类型A,所以T1A.第二个decltype产生表达式的类型,&如果表达式是左值则修改,&&如果表达式是xvalue则修改.表达式是左值,T2也是A&.