Рассмотрите следующий пример:
struct Scanner
{
template <typename T>
T get();
};
template <>
string Scanner::get()
{
return string("string");
}
template <>
int Scanner::get()
{
return 10;
}
int main()
{
Scanner scanner;
string s = scanner.get<string>();
int i = scanner.get<int>();
}
Scanner
класс используется для извлечения маркеров из некоторого источника. Вышеупомянутый код хорошо работает, но перестал работать, когда я пытаюсь get
другие целочисленные типы как a char
или unsigned int
. Код для чтения этих типов является точно тем же как кодом для чтения int
. Я мог просто копировать код для всех других целочисленных типов, которые я хотел бы считать, но я скорее определю один шаблон функции для всех целочисленных типов.
Я попробовал следующее:
struct Scanner
{
template <typename T>
typename enable_if<boost::is_integral<T>, T>::type get();
};
Который работает как очарование, но я не уверен, как добраться Scanner::get<string>()
функционировать снова. Так, как я могу написать код так, чтобы я мог сделать scanner.get<string>()
и scanner.get<any integral type>()
и имеет единственное определение для чтения всех целочисленных типов?
Обновление: вопрос о премии: Что, если я хочу принять больше чем один диапазон классов на основе некоторых черт? Например: как я должен приблизиться к этой проблеме, если я хочу иметь три get
функции, которые принимают (i) целочисленные типы (ii) типы с плавающей точкой (iii) строки, соответственно.
struct Scanner
{
template <typename T>
typename boost::enable_if<boost::is_integral<T>, T>::type get()
{
return 10;
}
template <typename T>
typename boost::disable_if<boost::is_integral<T>, std::string>::type get()
{
return "string";
}
};
Обновление «Что, если я хочу принять более одного диапазона классов на основе некоторых характеристик?»
struct Scanner
{
template <typename T>
typename boost::enable_if<boost::is_integral<T>, T>::type get()
{
return 10;
}
template <typename T>
typename boost::enable_if<boost::is_floating_point<T>, T>::type get()
{
return 11.5;
}
template <typename T>
std::string get(
typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0,
typename boost::disable_if<boost::is_integral<T>, T>::type* = 0)
{
return std::string("string");
}
};
Перейти к другому шаблону. Вот общий шаблон того, что вы хотите:
template <typename T, bool HasTrait = false>
struct scanner_impl;
template <typename T>
struct scanner_impl
{
// Implement as though the trait is false
};
template <typename T>
struct scanner_impl<true>
{
// Implement as though the trait is true
};
// This is the one the user uses
template <typename T>
struct scanner : scanner_impl<T, typename has_my_trait<T>::value>
{
};