【发布时间】:2020-01-24 21:48:13
【问题描述】:
作为我正在为一个项目实现的一些几何函数的一部分,我认为将可以输入库的类型限制为仅几何类型是一个好主意。所以我写了以下结构来帮助解决这个问题:
template<typename T>
struct Geometric {
static_assert(std::is_arithmetic_v<T>, "T Must be Arithmetic!");
static_assert(std::is_same_v<T, std::decay_t<T>>, "Must be raw type!");
};
//...
template<typename T>
struct point2 : Geometic<T> {
//...
};
然后,因为我的库需要使用遵守算术类型的所有常见约定的自定义类型(至少就本项目而言),我想出了一个简单的解决方案,将这种类型集成到库中是只需为该类型添加一个 std::is_arithmetic 条目:
using rational_t = boost::multiprecision::cpp_rational;
template<>
struct std::is_arithmetic<rational_t> : std::true_type {};
using rational_point = point2<rational_t>;
但是,此代码始终产生“T 必须是算术!”编译时的错误消息。所以我稍微深入研究了微软对这些类型特征的实现,发现了一些我没有预料到的东西:std::is_arithmetic_v<T> 的派生直接来自其他常量,而不是来自其关联的结构。 p>
//MSVC2019 Code found in 'xtr1common', line# 197
// STRUCT TEMPLATE is_arithmetic
template <class _Ty>
_INLINE_VAR constexpr bool is_arithmetic_v = // determine whether _Ty is an arithmetic type
is_integral_v<_Ty> || is_floating_point_v<_Ty>;
template <class _Ty>
struct is_arithmetic : bool_constant<is_arithmetic_v<_Ty>> {};
这当然阻碍了我的代码,因为我对 is_arithmetic<rational_t> 的专业化对 is_arithmetic_v<rational_t> 的定义完全没有影响。
这特别阻碍了我,因为我期待专业化反向工作,从is_arithmetic 派生is_arithmetic_v,正如CPPReference's page for this type trait 中详细说明的那样:
辅助变量模板
template< class T > inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
可能的实现
template< class T > struct is_arithmetic : std::integral_constant<bool, std::is_integral<T>::value || std::is_floating_point<T>::value> {};
MSVC 对这个特征的定义(以及许多其他特征,似乎遵循类似的模式)根据标准是否合法,或者这是实施中的错误?如果将来我需要专门化这些类型的常量,这样做的理想方法是什么?
【问题讨论】:
-
这很棘手,一方面,你应该能够专门化模板,因为没有明确的要求你不能。另一方面
Tis required to be an arithmetic type,所以没有专业化应该是有效的。不确定在这种情况下什么会获胜。 -
@NathanOliver Cppreference claims 不允许专门化来自
<type_traits>的模板(common_type除外)。 -
@HolyBlackCat 他们是对的
-
我只是要把这句话添加到每个特质的页面上。
标签: c++ visual-c++ c++14