16

我在http://codepad.org/ko8vVCDF上编写了一个使用模板函数的示例程序。

如何将模板函数限制为仅使用数字?(整数,双等)

#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;
}
4

7 回答 7

21

这可以通过使用SFINAE来实现,并且通过使用来自 Boost 或 C++11 的帮助程序更容易

促进:

#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:

#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;
}
于 2008-09-29T15:17:52.900 回答
19

你可以这样做:

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 重载的 NumbersOnly,您将收到错误消息:

NumbersOnly<int> justFine;
NumbersOnly<SomeClass> noDeal;
于 2008-09-29T12:01:06.337 回答
19

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

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

任何具有所有这些特性的类型都可以与您的函数一起使用——所以,如果我创建一个具有这些特性的新类型,您的函数就会在它上面运行——这很棒,不是吗?

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

实现这一点的另一种方法是创建一个特征模板——像这样

template<class T>
SumTraits
{
public:
  const static bool canUseSum = false;
}

然后将其专门用于您想要的课程:

template<>
class SumTraits<int>
{
  public:
    const static bool canUseSum = true;
};

然后在你的代码中,你可以写

if (!SumTraits<T>::canUseSum) {
   // throw something here
}

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

于 2008-09-29T12:04:13.600 回答
3

你就是这样做的。

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

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;
}
于 2008-09-29T12:25:20.070 回答
1

在这种情况下,为什么要限制类型?模板允许“静态鸭子类型”,因此在这种情况下您的sum函数所允许的任何内容都应该被允许。具体来说,唯一需要的操作T是添加赋值和初始化为 0,因此任何支持这两个操作的类型都可以工作。这就是模板的美妙之处。

(如果您将初始化程序更改T result = T();为等,那么它也适用于数字和字符串。)

于 2008-09-29T11:54:31.063 回答
1

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

我在谷歌上找到了以下内容:http: //artins.org/ben/programming/mactechgrp-artin-cpp-type-traits.pdf

于 2008-09-29T11:59:40.333 回答
1

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

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

于 2008-09-29T12:02:55.177 回答