Microsoft Visual Studio неправильно определяет значения свойств типа? - PullRequest
1 голос
/ 25 января 2020

Как часть некоторых функций Geometri c, которые я реализую для проекта, я подумал, что было бы неплохо помочь ограничить типы, которые могут быть переданы в библиотеку, только Geometri c Types. Итак, я написал следующую структуру, чтобы помочь с этим:

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> {
    //...
};

Затем, потому что моей библиотеке нужно использовать пользовательский тип, который подчиняется всем общим соглашениям арифметических типов c (по крайней мере, насколько это возможно). что касается этого проекта) я решил, что простое решение для интеграции этого типа в библиотеку состоит в том, чтобы просто добавить запись для 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 должно быть арифметика c! " сообщение об ошибке во время компиляции. Поэтому я немного покопался в реализации Microsoft этих черт типа и обнаружил нечто, чего я не ожидал: вывод 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_v из is_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> {};

Как и определение MST C этой черты (и многих других черт, которые, кажется, следовать аналогичным закономерностям) законным в соответствии со стандартом, или это ошибка при внедрении? Если мне нужно специализировать эти виды констант в будущем, каков идеоматический c способ сделать это?

1 Ответ

4 голосов
/ 25 января 2020

Специализированные шаблоны из <type_traits> (кроме std::common_type), по-видимому, недопустимы:

cppreference:

Ни один из шаблонов, определенных в <type_traits>, не может быть специализированным для типа, определенного программой, за исключением std::common_type.

Основная часть стандарта: (любезно предоставлено @NathanOliver)

[meta.rqmts] / 4 :

Если не указано иное, поведение программы, которая добавляет специализации для любого из шаблонов, указанных в этом подпункте [meta], не определено.

Таким образом, реализация, используемая MSV C соответствует.

Классический обходной путь - создать собственную черту (основанную на стандартной) и вместо этого специализировать ее.

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