C++ 限制模板功能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/148373/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:14:09  来源:igfitidea点击:

Restrict Template Function

c++templates

提问by Lennie De Villiers

I wrote a sample program at http://codepad.org/ko8vVCDFthat uses a template function.

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

How do I retrict the template function to only use numbers? (int, double etc.)

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

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

回答by Leon Timmermans

This is possible by using SFINAE, and made easier by using helpers from either Boost or C++11

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

Boost:

促进:

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

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

回答by Jeff Hillman

You can do something like this:

你可以这样做:

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 );
    };
};

You will get an error if you try to create a NumbersOnly that doesn't have a ValidateType overload:

如果您尝试创建一个没有 ValidateType 重载的 NumbersOnly,您将收到错误消息:

NumbersOnly<int> justFine;
NumbersOnly<SomeClass> noDeal;

回答by Lou Franco

The only way to restrict a template is to make it so that it uses something from the types that you want, that other types don't have.

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

So, you construct with an int, use + and +=, call a copy constructor, etc.

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

Any type that has all of these will work with your function -- so, if I create a new type that has these features, your function will work on it -- which is great, isn't it?

具有所有这些功能的任何类型都可以与您的函数一起使用——因此,如果我创建一个具有这些功能的新类型,您的函数将可以使用它——这很棒,不是吗?

If you want to restrict it more, use more functions that only are defined for the type you want.

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

Another way to implement this is by creating a traits template -- something like this

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

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

And then specialize it for the classes you want to be ok:

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

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

Then in your code, you can write

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

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

edit: as mentioned in the comments, you can use BOOST_STATIC_ASSERT to make it a compile-time check instead of a run-time one

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

回答by OldMan

That is how you do it.

你就是这样做的。

Comment the template specialization for double for example.. and it will not allow you to call that function with double as parameter. The trick is that if you try to call sum with a type that is not among the specializations of IsNumber, then the generic implementation is called, and that implementation makes something not allowed (call a private constructor).

例如,注释 double 的模板特化.. 它将不允许您使用 double 作为参数调用该函数。诀窍是,如果您尝试使用不在 的特化范围内的类型调用 sum IsNumber,则调用泛型实现,并且该实现会产生不允许的东西(调用私有构造函数)。

The error message is NOT intuitive unless you rename the IsNumberclass to something that sounds like an error message.

错误消息并不直观,除非您将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;
}

回答by Chris Jester-Young

Why would you want to restrict the types in this case? Templates allow "static duck typing", so anything allowed by what your sumfunction in this case should be allowed. Specifically, the only operation required of Tis add-assignment and initialisation by 0, so any type that supports those two operations would work. That's the beauty of templates.

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

(If you changed your initialiser to T result = T();or the like, then it would work for both numbers and strings, too.)

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

回答by kjensen

You could look into type traits (use boost, wait for C++0x or create your own).

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

I found the following on google: http://artins.org/ben/programming/mactechgrp-artin-cpp-type-traits.pdf

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

回答by xtofl

Indeed, there's no need to make it more stringent. Have a look at the string version (using the default constructor style advised by Chris Jester-Young) here...

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

Take care, too, for overflows - you might need a bigger type to contain intermediate results (or output results). Welcome to the realm of meta-programming, then :)

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