Давайте предположим, что у нас есть шаблонная функция "нечто":
template<class T>
void foo(T arg)
{ ... }
Я могу сделать специализацию для некоторого конкретного типа, например.
template<>
void foo(int arg)
{ ... }
Если бы я хотел использовать ту же специализацию для всех встроенных числовых типов (интервал, плавание, то дважды и т.д.) Я много раз писал бы те строки. Я знаю, что тело может быть выведено к другой функции, и просто вызов этого должен быть выполнен в теле каждой специализации, однако было бы более хорошо, если я мог бы постараться не писать это "пустое нечто (..." для каждого типа. Там возможность состоит в том, чтобы сказать компилятору, что я хочу использовать эту специализацию для всего этого, вводит?
Вы можете использовать std :: numeric_limits
, чтобы узнать, является ли тип числовым типом ( is_specialized
истинно для всех основных типов с плавающей запятой и целых чисел).
// small utility
template<bool> struct bool2type { };
// numeric
template<typename T>
void fooImpl(T arg, bool2type<true>) {
}
// not numeric
template<typename T>
void fooImpl(T arg, bool2type<false>) {
}
template<class T>
void foo(T arg)
{ fooImpl(arg, bool2type<std::numeric_limits<T>::is_specialized>()); }
С ускорением:
#include <boost/type_traits/is_scalar.hpp>
#include <iostream>
#include <string>
namespace detail
{
typedef const boost::true_type& true_tag;
typedef const boost::false_type& false_tag;
template <typename T>
void foo(const T& pX, true_tag)
{
std::cout << "special: " << pX << std::endl;
}
template <typename T>
void foo(const T& pX, false_tag)
{
std::cout << "generic: " << pX << std::endl;
}
}
template <typename T>
void foo(const T& pX)
{
detail::foo(pX, boost::is_scalar<T>());
}
int main()
{
std::string s = ":D";
foo(s);
foo(5);
}
Вы можете легко сделать это без ускорения:
#include <iostream>
#include <string>
// boolean stuff
template <bool B>
struct bool_type {};
typedef bool_type<true> true_type;
typedef bool_type<false> false_type;
// trait stuff
template <typename T>
struct is_scalar : false_type
{
static const bool value = false;
};
#define IS_SCALAR(x) template <> \
struct is_scalar<x> : true_type \
{ \
static const bool value = true; \
};
IS_SCALAR(int)
IS_SCALAR(unsigned)
IS_SCALAR(float)
IS_SCALAR(double)
// and so on
namespace detail
{
typedef const true_type& true_tag;
typedef const false_type& false_tag;
template <typename T>
void foo(const T& pX, true_tag)
{
std::cout << "special: " << pX << std::endl;
}
template <typename T>
void foo(const T& pX, false_tag)
{
std::cout << "generic: " << pX << std::endl;
}
}
template <typename T>
void foo(const T& pX)
{
detail::foo(pX, is_scalar<T>());
}
int main()
{
std::string s = ":D";
foo(s);
foo(5);
}
Вы можете написать небольшой скрипт (например, Perl) для генерации исходного файла для вас. Создайте массив, содержащий все типы, которые вы хотите специализировать, и попросите его записать заголовок функции для каждого. Вы даже можете встроить выполнение скрипта в свой make-файл, чтобы автоматически перезапустить его, если вы что-то измените.
Примечание: это предполагает, что реализация foo
может быть упрощена и подобна для каждого типа, например, просто вызывая реальную функцию реализации. Но он избегает кучи шаблонов / препроцессоров, которые могут заставить будущего сопровождающего почесать затылок.
Вы можете использовать подход с препроцессором.
foo.inc:
template<>
void foo(TYPE arg)
{ /* do something for int, double, etc. */ }
foo.h:
template<class T>
void foo(T arg)
{ /*do something */ }
#define TYPE int
#include "foo.inc"
#undef TYPE
#define TYPE double
#include "foo.inc"
#undef TYPE
и т. Д.
возможно, вы можете определить функцию шаблона по умолчанию, которая будет работать со всеми собственными типами, и делегировать специализацию пользовательских типов пользователю