25

只是declval<T>()替代(*(T*)NULL)在 decltype 中获取 T 的实例而不需要担心 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;

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

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

4

2 回答 2

30

declval()其优点是,如果在评估的上下文中使用它(即 odr-used),则程序格式错误(20.2.4p2),并且需要发出诊断(每 1.4p1)。通常这是通过static_assert库中的 a 强制执行的:

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 AE1是一个纯右值(在 C++14 中它是一个 xvalue。即使在 C++11 模式下,一些编译器也可能会将它视为一个 xvalue),E2是一个 xvalue。E3是一个左值,又E4是一个 xvalue。

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

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

于 2013-02-02T12:45:30.163 回答