首页 > 解决方案 > Microsoft Visual Studio 是否不正确地定义了类型特征的值?

问题描述

作为我正在为一个项目实现的一些几何函数的一部分,我认为将可以输入库的类型限制为仅几何类型是一个好主意。所以我写了以下结构来帮助解决这个问题:

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>直接来自其他常量,而不是来自其关联的结构。

//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_vis_arithmetic因为它在CPPReference 的页面上对此类型特征进行了详细说明:

辅助变量模板

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 对这个特征(以及许多其他特征,似乎遵循类似模式)的定义是否合法,或者这是实现中的错误?如果将来我需要专门化这些常量,这样做的理想方法是什么?

标签: c++visual-c++c++14

解决方案


似乎不允许专门化来自<type_traits>(除)的模板:std::common_type

cpp参考:

除了. <type_traits>_std::common_type

标准的相关部分是:(@NathanOliver 提供)

[meta.rqmts]/4

除非另有说明,否则为本子条款 [meta] 中指定的任何模板添加特化的程序的行为是未定义的。

所以 MSVC 使用的实现是一致的。

经典的解决方法是制作自己的特征(基于标准特征)并专门化它。

template <typename T>
struct IsArithmetic : std::is_arithmetic<T> {};

推荐阅读