C++ 限制模板函数

C++ 限制模板函数,c++,templates,C++,Templates,我编写了一个使用模板函数的示例程序 如何检索模板函数以仅使用数字?(整数、双精度等) #包括 #包括 使用名称空间std; 模板 T和(向量&a) { T结果=0; int size=a.size(); 对于(int i=0;i

我编写了一个使用模板函数的示例程序

如何检索模板函数以仅使用数字?(整数、双精度等)

#包括
#包括
使用名称空间std;
模板
T和(向量&a)
{
T结果=0;
int size=a.size();
对于(int i=0;icout在这种情况下,为什么要限制类型?模板允许“静态鸭子类型”,因此在这种情况下,
sum
函数允许的任何操作都应该被允许。具体地说,
T
所需的唯一操作是通过0添加赋值和初始化,因此任何支持这两个操作的类型都可以工作。这就是模板的优点


(如果您将初始值设定项更改为
T result=T();
或类似的,那么它也适用于数字和字符串。)

您可以查看类型特征(使用boost,等待C++0x或创建自己的)


我在谷歌上发现了以下内容:

你可以这样做:

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 );
    };
};
模板
类别编号仅限
{
私人:
void ValidateType(int&i)const{}
void ValidateType(long&l)const{}
void ValidateType(double&d)const{}
void ValidateType(float&f)const{}
公众:
NumbersOnly()
{
无效;
ValidateType(有效);
};
};
如果尝试创建没有ValidateType重载的NumbersOnly,将出现错误:

NumbersOnly<int> justFine;
NumbersOnly<SomeClass> noDeal;
numbers仅限罚款;
数只结;

事实上,没有必要使其更严格。请查看字符串版本(使用Chris Jester Young建议的默认构造函数样式)


也要注意溢出-您可能需要更大的类型来包含中间结果(或输出结果)。欢迎来到元编程领域:)

限制模板的唯一方法是使其使用您想要的类型中的某些内容,而其他类型没有

因此,使用int构造,使用+和+=,调用复制构造函数,等等

任何具有所有这些特性的类型都可以与您的函数一起工作——因此,如果我创建一个具有这些特性的新类型,您的函数也可以与之一起工作——这很好,不是吗

如果要对其进行更多限制,请使用更多仅为所需类型定义的函数

实现这一点的另一种方法是创建一个traits模板——类似这样的

template<class T>
SumTraits
{
public:
  const static bool canUseSum = false;
}
模板
萨姆特
{
公众:
const static bool canUseSum=false;
}
然后专门针对您想要确定的类:

template<>
class SumTraits<int>
{
  public:
    const static bool canUseSum = true;
};
模板
阶级特征
{
公众:
const static bool canUseSum=true;
};
然后在代码中,您可以编写

if (!SumTraits<T>::canUseSum) {
   // throw something here
}
if(!SumTraits::canUseSum){
//扔东西到这里
}

编辑:如注释中所述,您可以使用BOOST_STATIC_ASSERT使其成为编译时检查,而不是运行时检查

例如,注释double的模板专门化。它将不允许您使用double作为参数调用该函数。诀窍是,如果您尝试使用不属于
IsNumber
专门化的类型调用sum,则会调用泛型实现,而该实现会使某些内容不被允许(调用私有构造函数)

除非将
IsNumber
类重命名为听起来像错误消息的名称,否则错误消息不是直观的

#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;
}
#包括
#包括
使用名称空间std;
模板结构IsNumber{
私人:
IsNumber(){}
};
模板结构IsNumber{
IsNumber(){};
};
模板结构IsNumber{
IsNumber(){};
};
模板结构IsNumber{
IsNumber(){};
};
模板
T和(向量&a)
{
ISN数检验;
T结果=0;
int size=a.size();
对于(int i=0;i
促进:

#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;
}
#包括
#包括
#包括
模板
typename boost::enable_if::type
总和(常数标准::向量和向量)
{
typedef typename std::vector::size\u type size\u type;
T结果;
size_type size=vec.size();
对于(大小\类型i=0;i
C++11:

#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;
}
#包括
#包括
模板
typename std::enable_if::type
总和(常数标准::向量和向量)
{
T结果;
用于(自动项目:vec)
结果+=项目;
返回结果;
}

您也可以使用BOOST\u STATIC\u ASSERT在编译时强制执行条件。这是一个运行时检查,这不是一个好主意,因为这可以在编译时执行。SFINAE是解决此问题的方法,而不是BOOST\u STATIC\u ASSERT有自己执行静态断言的方法。(如果您介意使用BOOST),例如使用开关(ASDF){case 0:case Something nozzero:break;}
是限制
的唯一方法,稍晚一点,
是另一种……限制
的方法。这里有点不准确……我要说的是扩展到“类型安全”“为了避免我不得不记录并坚持我对算术运算符和转换的行为所做的一组有限的假设,非内置类型可能无法满足这些假设"。否则,您可能会在将来更改实现,并需要更多的假设。因此,例如,当前它使用+=。如果以后更改为使用+,则类型仅支持+=的用户将被删除。例如,如此简单的示例,我想不出任何其他可行的实现更改,并且重载+=和not+会带来任何麻烦方法,但希望yswim.onebyone:Hear,Hear!记录“接口”是一种方法,与动态语言的工作方式基本相同
#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;
}