首页 > 解决方案 > 我们什么时候需要模板元编程中的标签调度?

问题描述

我是模板元编程的新手,我正在观看 Jody Hagins 的类型特征谈话第二部分。我想复制一个函数重载解析示例,以使用以下方法检测给定类型是否为常量:

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 TypeTagT事情会按预期工作:

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类型?

标签: c++templatesmetaprogrammingtemplate-meta-programming

解决方案


第一个示例不起作用的原因是函数参数中的顶级 const被忽略,因此is_const(T)is_const(T const)是相同的函数签名。如果const不是顶级的,则函数签名是不同的,例如is_const(T*)is_const(T* const)是不同的。

在您的第二个示例中,is_const(TypeTag<T>)andis_const(TypeTag<T const>)是不同的,因为TypeTag<T>andTypeTag<T const>是不相关的类型。

但是,我认为您的使用不TypeTag符合“标签调度”的条件。


推荐阅读