Ответ 1
[declval] указывает, что:
Если эта функция используется odr (3.2), программа плохо сформирована.
Это в основном это. В случае использования функций odr-use из [basic.def.odr]:
Функция, имя которой отображается как потенциально оцененное выражение, используется как odr если это уникальный результат поиска или выбранный элемент набора перегруженных функций (3.4, 13.3, 13.4), если он не является чистой виртуальной функцией, и либо его имя явно не квалифицировано, либо формы выражения указатель на элемент (5.3.1).
Но также:
Выражение потенциально оценивается, если оно не является неоцененным операндом (п. 5) или подвыражением его.
И [dcl.type.simple]:
Операндом спецификатора
decltype
является неоцениваемый операнд (пункт 5).
Итак, в decltype(std::declval<const void>)
, std::declval
не оценивается потенциально и, следовательно, не используется odr. Так как один критерий на declval
для программы будет плохо сформирован, и мы не встречаем его, я думаю, что libstdС++ ошибочно испускает статическое утверждение.
Хотя я не думаю, что это вещь libstС++. Я думаю, что это больше вопрос о том, когда срабатывает static_assert
. Реализация libstdС++ declval
:
template<typename _Tp>
struct __declval_protector
{
static const bool __stop = false;
static typename add_rvalue_reference<_Tp>::type __delegate();
};
template<typename _Tp>
inline typename add_rvalue_reference<_Tp>::type
declval() noexcept
{
static_assert(__declval_protector<_Tp>::__stop,
"declval() must not be used!");
return __declval_protector<_Tp>::__delegate();
}
Оба gcc и clang запускают в этом контексте static_assert
(но, очевидно, не с decltype(std::declval<const void>())
, хотя в обоих случаях мы находимся в неоценимом контексте. стандартное, какое правильное поведение имеет отношение к запуску static_assert
s.