Is declval
just a replacement for the old trick of (*(T*)NULL)
to get an instance of T in a decltype without needing to worry about T\'s
declval()
has the advantage that if it is used in an evaluated context (i.e., odr-used) then the program is ill-formed (20.2.4p2), and a diagnostic is required to be issued (per 1.4p1). Typically this is enforced through a static_assert
in the library:
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
also works on reference types:
using S = int &;
using T = decltype(std::declval<S>());
using U = decltype(*(S *)nullptr); // fails
Where the type is not a reference type, declval
will give an rvalue type where nullptr
gives an lvalue.
No, declval<T>()
is not the same as (*(T*)nullptr)
. And decltype(expr.bar)
is not the same as decltype((expr.bar))
.
The former comparison compares expressions. The latter use of decltype
inspects the expression and the former use of decltype
inspects the declared type of expr.bar
. So you have to paren your uses of the decltype
operand to make a useful comparison of the types and you will find they are different.
struct A {};
struct B {
A a;
};
// E1: B().a
// E2: declval<A>().a
// E3: (*(B*)0).a
// E4: ((B&&)(*(B*)0)).a
In these 4 expressions, all expressions have type A
. E1
is a prvalue (in C++14 it is an xvalue. Some compilers probably will treat it as an xvalue even in their C++11 mode), E2
is an xvalue. E3
is an lvalue and E4
is an xvalue again.
// T1: decltype((*(B*)0).a)
// T2: decltype(((*(B*)0).a))
In these two types, the first decltype gives the type of the member named by the expression. The member has type A
, so T1
is A
. The second decltype yields the type of the expression, modified by &
if the expression is an lvalue and modified by &&
if the expression is an xvalue. The expression is an lvalue, so T2
is A&
.