【问题标题】:Is Microsoft Visual Studio improperly defining the values of Type Traits?Microsoft Visual Studio 是否不正确地定义了类型特征的值?
【发布时间】: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&lt;T&gt; 的派生直接来自其他常量,而不是来自其关联的结构。 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&lt;rational_t&gt; 的专业化对 is_arithmetic_v&lt;rational_t&gt; 的定义完全没有影响。

这特别阻碍了我,因为我期待专业化反向工作,从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 对这个特征的定义(以及许多其他特征,似乎遵循类似的模式)根据标准是否合法,或者这是实施中的错误?如果将来我需要专门化这些类型的常量,这样做的理想方法是什么?

【问题讨论】:

  • 这很棘手,一方面,你应该能够专门化模板,因为没有明确的要求你不能。另一方面T is required to be an arithmetic type,所以没有专业化应该是有效的。不确定在这种情况下什么会获胜。
  • @NathanOliver Cppreference claims 不允许专门化来自&lt;type_traits&gt; 的模板(common_type 除外)。
  • @HolyBlackCat 他们是对的
  • 我只是要把这句话添加到每个特质的页面上。

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


【解决方案1】:

似乎不允许使用来自&lt;type_traits&gt;std::common_type 除外)的专用模板:

cppreference:

&lt;type_traits&gt; 中定义的模板都不能专门用于程序定义的类型,std::common_type 除外。

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

[meta.rqmts]/4:

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

所以MSVC使用的实现是符合的。

经典的解决方法是创建自己的特征(基于标准特征)并对其进行专门化。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多