Как я проверяю, что мой шаблонный класс имеет определенный тип класса?

В моей шаблонной-ized функции я пытаюсь проверить, что тип T имеет определенный тип. Как я сделал бы это?

p/s я знал шаблонную спецификацию путь, но я не хочу делать это.

template<class T> int foo(T a) {
  // check if T of type, say, String?
}

Спасибо!

25
задан Benoît 9 February 2013 в 08:13
поделиться

7 ответов

Я полагаю, вы могли бы использовать std :: type_info , возвращаемый оператором typeid

7
ответ дан 28 November 2019 в 17:45
поделиться

хм, потому что у меня была большая часть того же кода до части "спецификация" .

Вы можете использовать перегрузку, но если большая часть кода будет работать для любого типа, вы можете рассмотреть возможность выделения отличающейся части в отдельную функцию и перегрузить ее.

template <class T>
void specific(const T&);

void specific(const std::string&);

template <class T>
void something(const T& t)
{
    //code that works on all types
    specific(t);
    //more code that works on all types
}
11
ответ дан 28 November 2019 в 17:45
поделиться

Я подозреваю, что кто-то должен сказать вам, почему не следует избегать использования перегрузки или специализации. Подумайте:

template<class T> int foo(T a) {
  if(isAString<T>()) {
    return a.length();
  } else {
    return a;
  }
}

На первый взгляд вы можете подумать, что он будет работать и для int , потому что он будет пытаться вызвать length только для строк. Но эта интуиция ошибочна: компилятор по-прежнему проверяет ветвь строки, даже если эта ветвь не выполняется во время выполнения. И он обнаружит, что вы пытаетесь вызвать функцию-член для неклассов, если T является int.

Вот почему вам следует разделить код, если вам нужно другое поведение. Но лучше использовать перегрузку вместо специализации, так как легче понять, как с ней все работает.

template<class T> int foo(T a) {
  return a;
}

int foo(std::string const& a) {
  return a.length();
}

Вы также лучше разделите код для разных вариантов поведения. Это уже не все вместе. Обратите внимание, что при перегрузке параметры могут иметь разные формы типов, и компилятор по-прежнему будет использовать правильную версию, если оба совпадают одинаково хорошо, как в данном случае: один может быть ссылкой, а другой - нет.

7
ответ дан 28 November 2019 в 17:45
поделиться

Вместо проверки типа используйте специализации. В противном случае не используйте шаблоны.

template<class T> int foo(T a) {
      // generic implementation
}
template<> int foo(SpecialType a) {
  // will be selected by compiler 
}

SpecialType x;
OtherType y;
foo(x); // calls second, specialized version
foo(y); // calls generic version
49
ответ дан 28 November 2019 в 17:45
поделиться

Вы можете проверить с помощью type_traits (доступно в Boost и TR1) (например, is_same или is_convertible ), если вы действительно хотите избежать специализации.

4
ответ дан 28 November 2019 в 17:45
поделиться

Если вас не волнует время компиляции, вы можете использовать boost::is_same.

bool isString = boost::is_same<T, std::string>::value;

Начиная с C++11, это теперь часть стандартной библиотеки

bool isString = std::is_same<T, std::string>::value
13
ответ дан 28 November 2019 в 17:45
поделиться

Вы можете выполнять статические проверки полученного типа (см. Библиотеку признаков типа повышения), но если вы не используете специализацию (или перегрузки, как @litb правильно указывает) в тот или иной момент вы не сможете предоставить различные конкретные реализации в зависимости от типа аргумента.

Если у вас нет особой причины (которую вы можете добавить к вопросу) не использовать специализацию в интерфейсе, просто сделайте specialize.

template <> int subtract( std::string const & str );
2
ответ дан 28 November 2019 в 17:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: