Как ограничить класс шаблона определенными встроенными типами? - программирование
Подтвердить что ты не робот

Как ограничить класс шаблона определенными встроенными типами?

Эта проблема обсуждалась несколько раз, но все решения, которые я нашел, либо не работали, либо основывались на boost static assert. Моя проблема проста. У меня есть класс, и я хочу только разрешить реальные типы (double и float). Мне нужна ошибка времени компиляции, если я пытаюсь создать экземпляр класса с типом, отличным от float или double. Я использую Visual С++ 11. Вот что я пробовал:

template <typename RealType>
class A
{
  // Warning C4346
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value);
}


template <typename RealType>
class A
{
  // Error C2062: type 'unknown' unexpected
  static_assert(decltype(RealType) == double || decltype(RealType) == float);
}

Любые идеи? Спасибо заранее!

4b9b3361

Ответ 1

Одним из решений, которое я видел, является использование std::enable_if в псевдониме типа. Что-то вроде:

using value_type = typename std::enable_if<
                    std::is_same<float, RealType>::value ||
                    std::is_same<double, RealType>::value,
                    RealType
                >::type;

value_type существует только в том случае, если RealType - это точно float или double. В противном случае тип undefined и сбой компиляции.

Я бы предупредил о том, чтобы быть слишком строгим с типами. Шаблоны такие же мощные, как и отчасти потому, что утка, набираемая ими, означает, что любой тип, который можно использовать так, как вы хотите его использовать, будет работать. Запрещение типов для запрещения типов обычно не дает вам многого и может сделать вещи менее гибкими, чем они могли бы быть. Например, вы не сможете использовать тип с большей точностью, например, с большим десятичным типом.

Ответ 2

В первом примере static_assert должен взять второй параметр, который будет строковым литералом, в противном случае он считается недействительным (изменение: удаление второго параметра является законным с С++ 17). И этот второй аргумент не может быть установлен по умолчанию.

Второй пример неверен по нескольким причинам:

  • decltype должен использоваться для выражения, а не для типа.
  • Вы просто не можете сравнивать типы с ==, правильный способ сделать это - это то, что вы пытаетесь выполнить с первой попытки с помощью std::is_same.

Итак, правильный способ сделать то, что вы пытаетесь достичь:

#include <type_traits>

template <typename RealType>
class A
{
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value,
                "some meaningful error message");
};

Кроме того, я уверен, вы пытаетесь сжать свой шаблон до значений с плавающей запятой. Для этого вы можете использовать признак std::is_floating_point:

#include <type_traits>

template <typename RealType>
class A
{
  static_assert(std::is_floating_point<RealType>::value,
                "class A can only be instantiated with floating point types");
};

И в качестве бонуса возьмите этот онлайн-пример.

Ответ 3

Таким образом, он также позволяет специализацию для различных типов:

template<typename T, typename Enable = void>
class A {
/// Maybe no code here or static_assert(false, "nice message");
};

/// This specialization is only enabled for double or float.
template<typename T>
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> {

};