Является declval<T>()
просто замена старой уловки (*(T*)NULL)
получить экземпляр T в типе decl, не беспокоясь о конструкторе 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 — это больше, чем замена, каковы различия и где это полезно?
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!
declval
также работает на ссылочных типах:
using S = int &;
using T = decltype(std::declval<S>());
using U = decltype(*(S *)nullptr); // fails
Где тип не ссылочный тип, declval
даст тип значения где nullptr
дает lvalue.
Нет, 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 выражениях все выражения имеют тип A
, E1
является prvalue (в C ++ 14 это xvalue. Некоторые компиляторы, вероятно, будут обрабатывать его как xvalue даже в режиме C ++ 11), E2
это xvalue. E3
это lvalue и E4
снова значение xvalue
// T1: decltype((*(B*)0).a)
// T2: decltype(((*(B*)0).a))
В этих двух типах первый decltype дает тип члена, названного выражением. Член имеет тип A
, так T1
является A
, Второй decltype возвращает тип выражения, измененный &
если выражение является lvalue и изменено &&
если выражение является xvalue. Выражение является lvalue, поэтому T2
является A&
,