【发布时间】:2021-12-04 01:11:23
【问题描述】:
我是模板元编程的新手,我正在观看 Jody Hagins 的 type traits talk part II。我想复制一个函数重载解析示例,以使用以下方法检测给定类型是否为常量:
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 的调用不明确。如果我使用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 类型?
【问题讨论】:
-
is_const(T) 和 is_const(T const) 相同,因此有歧义。
标签: c++ templates metaprogramming template-meta-programming