sylvia0x97
sylvia0x97

Reputation: 1

When do we need Tag Dispatching in Template Metaprogramming?

I am new to template metaprogramming and I was watching the type traits talk part II by Jody Hagins. I wanted to replicate a function overload resolution example to detect whether a given type is constant using the following:

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);

The above static assertion produces a compiler error saying call to is_const is ambiguous. If I use a TypeTag to enclose T in my template declarations, things work as expected:

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);

I am confused as to why the first declarations without TypeTag encapsulation are ambiguous. My guess is it has something to do with declval return type being T for cv-qualified types but then I do not understand how the second case works.

Is it because in the first case declval<int const> has return type int but in the second case declval<TypeTag<int const>> has return type TypeTag<int const> so the compiler picks the first template specialization where T is replaced with int and the template invocation looks like this:

<>
std::true_type is_const<TypeTag<int const>>;

If my guess is correct, is there a general practice to use tag dispatching with a TypeTag (empty struct template) to guard against cv-qualified types?

Upvotes: 0

Views: 247

Answers (1)

Eugene
Eugene

Reputation: 7528

The reason the 1st example does not work is that top-level const in a function argument is ignored, so is_const(T) and is_const(T const) are the same function signatures. If const is not top-level, function signatures are different, e.g. is_const(T*) and is_const(T* const) are different.

In your 2nd example, is_const(TypeTag<T>) and is_const(TypeTag<T const>) are different because TypeTag<T> and TypeTag<T const> are unrelated types.

However, I don't think that your use of TypeTag qualifies as "tag dispatch".

Upvotes: 1

Related Questions