В моей шаблонной-ized функции я пытаюсь проверить, что тип T имеет определенный тип. Как я сделал бы это?
p/s я знал шаблонную спецификацию путь, но я не хочу делать это.
template<class T> int foo(T a) {
// check if T of type, say, String?
}
Спасибо!
Я полагаю, вы могли бы использовать std :: type_info
, возвращаемый оператором typeid
хм, потому что у меня была большая часть того же кода до части "спецификация" .
Вы можете использовать перегрузку, но если большая часть кода будет работать для любого типа, вы можете рассмотреть возможность выделения отличающейся части в отдельную функцию и перегрузить ее.
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
}
Я подозреваю, что кто-то должен сказать вам, почему не следует избегать использования перегрузки или специализации. Подумайте:
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();
}
Вы также лучше разделите код для разных вариантов поведения. Это уже не все вместе. Обратите внимание, что при перегрузке параметры могут иметь разные формы типов, и компилятор по-прежнему будет использовать правильную версию, если оба совпадают одинаково хорошо, как в данном случае: один может быть ссылкой, а другой - нет.
Вместо проверки типа используйте специализации. В противном случае не используйте шаблоны.
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
Вы можете проверить с помощью type_traits
(доступно в Boost и TR1) (например, is_same
или is_convertible
), если вы действительно хотите избежать специализации.
Если вас не волнует время компиляции, вы можете использовать boost::is_same.
bool isString = boost::is_same<T, std::string>::value;
Начиная с C++11, это теперь часть стандартной библиотеки
bool isString = std::is_same<T, std::string>::value
Вы можете выполнять статические проверки полученного типа (см. Библиотеку признаков типа повышения), но если вы не используете специализацию (или перегрузки, как @litb правильно указывает) в тот или иной момент вы не сможете предоставить различные конкретные реализации в зависимости от типа аргумента.
Если у вас нет особой причины (которую вы можете добавить к вопросу) не использовать специализацию в интерфейсе, просто сделайте specialize.
template <> int subtract( std::string const & str );