Search code examples
c++c++11decltype

Is declval<T>() the same as (*(T*)nullptr)?


Is declval<T>() 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 constructor?

Here is some sample code:

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;

which prints 1 because T1 and T2 are the same type.

If declval is more than a replacement, what are the differences and where is it useful?


Solution

  • 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.