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