假设我们有一个模板函数“foo”:
template<class T>
void foo(T arg)
{ ... }
我可以为某些特定类型进行专业化,例如
template<>
void foo(int arg)
{ ... }
如果我想对所有内置数值类型(int,float,double等)使用相同的特化,我会多次写这些行。我知道身体可以被扔到另一个功能,并且只是在每个专业的身体中调用它,但是如果我能避免为每种类型写出这个“void foo(...”)会更好。是否有有没有可能告诉编译器我想对所有这些类型使用这个特化?
答案 0 :(得分:19)
您可以使用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>()); }
答案 1 :(得分:3)
您可以使用预处理器的方法。
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
等
答案 2 :(得分:3)
有了提升:
#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);
}
答案 3 :(得分:0)
也许您可以定义一个适用于所有本机类型的默认模板函数,并将自定义类型的专业化委托给用户
答案 4 :(得分:0)
您可以编写一个小脚本(例如Perl)来为您生成源文件。创建一个包含您想要专门化的所有类型的数组,并让它为每个类型写出函数头。您甚至可以在makefile中嵌入脚本执行,以便在更改内容时自动重新运行它。
注意:这假设foo
的实现对于每种类型都可以是微不足道的,例如,简单地调用实际的实现函数。但是它避免了一堆模板/预处理器mumbo-jumbo,可能会让未来的维护者抓住他的头脑。
答案 5 :(得分:0)
这是对Johannes解决方案的改进,但更易于阅读。只需在函数内部进行类型检查:
template<typename T>
void foo(T arg)
{
if (numeric_limits<T>::is_specialized) // not a runtime check - compile time constant
{
}
else
{
}
}
使用类型特征(本身是模板特化)可以用一个易于阅读的功能模板替换一堆模板特化