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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With