#c #templates #metaprogramming #template-meta-programming
Вопрос:
Я новичок в метапрограммировании шаблонов и наблюдал за второй частью беседы о чертах типа Джоди Хагинс. Я хотел воспроизвести пример разрешения перегрузки функции, чтобы определить, является ли данный тип постоянным, используя следующее:
namespace detail {
template <typename T>
std::true_type is_const(T const);
template <typename T>
std::false_type is_const(T);
} // namespace detail
template <typename T>
using is_constant = decltype(detail::is_const(std::declval<T>()));
static_assert(is_constant<int const>::value);
Приведенное выше статическое утверждение приводит к ошибке компилятора, в которой говорится, что вызов is_const
неоднозначен. Если я использую a TypeTag
для включения T
в свои объявления шаблонов, все работает так, как ожидалось:
template <typename T>
struct TypeTag {};
namespace detail {
template <typename T>
std::true_type is_const(TypeTag<T const>);
template <typename T>
std::false_type is_const(TypeTag<T>);
} // namespace detail
template <typename T>
using is_constant = decltype(detail::is_const(std::declval<TypeTag<T>>()));
static_assert(is_constant<int const>::value);
Я не понимаю, почему первые объявления без TypeTag
инкапсуляции неоднозначны. Я предполагаю, что это как-то связано с declval
тем, что возвращаемый тип предназначен T
для cv-qualified
типов, но тогда я не понимаю, как работает второй случай.
Это потому, что в первом случае declval<int const>
имеет тип возврата int, но во втором случае declval<TypeTag<int const>>
имеет тип возврата TypeTag<int const>
, поэтому компилятор выбирает первую специализацию шаблона, где T
заменяется на int, и вызов шаблона выглядит следующим образом:
<>
std::true_type is_const<TypeTag<int const>>;
Если мое предположение верно, существует ли общая практика использования диспетчеризации тегов с TypeTag
(пустым шаблоном структуры) для защиты от cv-qualified
типов?
Комментарии:
1. is_const(T) и is_const(T const) одинаковы, отсюда и неоднозначность.
Ответ №1:
Причина, по которой 1-й пример не работает, заключается в том, что верхний уровень const
в аргументе функции игнорируется, поэтому is_const(T)
и is_const(T const)
являются одинаковыми сигнатурами функций. Если const
не является верхним уровнем, сигнатуры функций различны, например is_const(T*)
, и is_const(T* const)
различны.
В вашем 2-м примере is_const(TypeTag<T>)
и is_const(TypeTag<T const>)
отличаются, потому TypeTag<T>
что и TypeTag<T const>
являются несвязанными типами.
Однако я не думаю, что ваше использование TypeTag
квалифицируется как «отправка тегов».