c++ - 我们什么时候需要模板元编程中的标签调度?
问题描述
我是模板元编程的新手,我正在观看 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 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
类型?
解决方案
第一个示例不起作用的原因是函数参数中的顶级 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
符合“标签调度”的条件。
推荐阅读
- atom-editor - 如何在 php-cs-fixer 在 Atom 中更正错误之前显示错误?
- angular - 带有特定查询参数的后端匹配 API 路径的 Angular 代理
- python - scipy.optimize.minimize 将数组写入数组并且收敛失败
- azure-devops - 用于同时支持 docker linux 和 windows 容器的 azure windows vm
- java - 从一个单词到另一个单词或结尾检索字符串的一部分
- swift - 无法从特定 URL 下载图像
- websocket - 使用 WebSocket 的原始 javascript GraphQL 订阅不起作用
- javascript - Zone.js 检测到 ZoneAwarePromise `(window|global).Promise` 已被覆盖
- python - 排除字符的 Python 正则表达式
- laravel - 使用 Laravel Horizon 的 redis-cli 上存在缺失的 failed_jobs