Restrict Template Function
我在http://codepad.org/ko8vvcdf上编写了一个使用模板函数的示例程序。
如何检索模板函数以仅使用数字?(int、double等)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include <vector> #include <iostream> using namespace std; template <typename T> T sum(vector<T>& a) { T result = 0; int size = a.size(); for(int i = 0; i < size; i++) { result += a[i]; } return result; } int main() { vector<int> int_values; int_values.push_back(2); int_values.push_back(3); cout <<"Integer:" << sum(int_values) << endl; vector<double> double_values; double_values.push_back(1.5); double_values.push_back(2.1); cout <<"Double:" << sum(double_values); return 0; } |
这可以通过使用sFIAE来实现,并且通过使用Boost或C++ 11的帮助器来变得更容易。
促进:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <vector> #include <boost/utility/enable_if.hpp> #include <boost/type_traits/is_arithmetic.hpp> template<typename T> typename boost::enable_if<typename boost::is_arithmetic<T>::type, T>::type sum(const std::vector<T>& vec) { typedef typename std::vector<T>::size_type size_type; T result; size_type size = vec.size(); for(size_type i = 0; i < size; i++) { result += vec[i]; } return result; } |
C++ 11:
1 2 3 4 5 6 7 8 9 10 11 12 | #include <vector> #include <type_traits> template<typename T> typename std::enable_if<std::is_arithmetic<T>::value, T>::type sum(const std::vector<T>& vec) { T result; for (auto item : vec) result += item; return result; } |
你可以这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | template <class T> class NumbersOnly { private: void ValidateType( int &i ) const {} void ValidateType( long &l ) const {} void ValidateType( double &d ) const {} void ValidateType( float &f ) const {} public: NumbersOnly() { T valid; ValidateType( valid ); }; }; |
如果尝试仅创建一个没有validateType重载的数字,则会出现错误:
1 2 | NumbersOnly<int> justFine; NumbersOnly<SomeClass> noDeal; |
限制模板的唯一方法是使其使用您想要的类型,而其他类型没有的类型。
所以,使用int构造,使用+和+=,调用一个复制构造函数,等等。
任何具有所有这些特性的类型都可以使用您的函数——所以,如果我创建一个具有这些特性的新类型,您的函数就可以使用它——这很好,不是吗?
如果您想更多地限制它,请使用更多只为您想要的类型定义的函数。
实现这一点的另一种方法是创建一个特性模板——类似于这样
1 2 3 4 5 6 | template<class T> SumTraits { public: const static bool canUseSum = false; } |
然后将它专门用于您想要确定的类:
1 2 3 4 5 6 | template<> class SumTraits<int> { public: const static bool canUseSum = true; }; |
然后在代码中,您可以编写
1 2 3 | if (!SumTraits<T>::canUseSum) { // throw something here } |
编辑:正如注释中所提到的,可以使用boost-static-assert将其设置为编译时检查,而不是运行时检查。
你就是这样做的。
例如,对double的模板专门化进行注释。它不允许您使用double作为参数调用该函数。诀窍是,如果您尝试使用不属于
除非将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | #include <vector> #include <iostream> using namespace std; template<class T> struct IsNumber{ private: IsNumber(){} }; template<> struct IsNumber<float>{ IsNumber(){}; }; template<> struct IsNumber<double>{ IsNumber(){}; }; template<> struct IsNumber<int>{ IsNumber(){}; }; template <typename T> T sum(vector<T>& a) { IsNumber<T> test; T result = 0; int size = a.size(); for(int i = 0; i < size; i++) { result += a[i]; } return result; } int main() { vector<int> int_values; int_values.push_back(2); int_values.push_back(3); cout <<"Integer:" << sum(int_values) << endl; vector<double> double_values; double_values.push_back(1.5); double_values.push_back(2.1); cout <<"Double:" << sum(double_values); return 0; } |
事实上,没有必要让它更严格。请看一下字符串版本(使用ChrisJester Young建议的默认构造函数样式)。
同样要注意溢出-您可能需要更大的类型来包含中间结果(或输出结果)。欢迎来到元编程领域,那么:)
您可以查看类型特性(使用Boost、等待C++ 0x或创建自己的)。
我在谷歌上找到了以下信息:http://artins.org/ben/programming/mactechgrp-artin-cpp-type-traits.pdf
在这种情况下,为什么要限制类型?模板允许"静态鸭式键入",因此在这种情况下,您的
(如果您将初始化器更改为