Когда нам нужна отправка тегов в метапрограммировании шаблонов?

#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 квалифицируется как «отправка тегов».