Подтвердить что ты не робот

Ограничить функцию шаблона

Я написал образец программы в http://codepad.org/ko8vVCDF, который использует функцию шаблона.

Как получить функцию шаблона только для использования чисел? (int, double и т.д.)

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

Ответ 1

Единственный способ ограничить шаблон - сделать так, чтобы он использовал что-то из тех типов, которые вы хотите, чтобы другие типы не имели.

Итак, вы строите с помощью 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
}

edit: как указано в комментариях, вы можете использовать BOOST_STATIC_ASSERT, чтобы сделать его временем проверки компиляции вместо времени выполнения

Ответ 2

Это возможно, используя SFINAE и упростившись с помощью помощников из Boost или С++ 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;
}

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

Ответ 3

Вы можете сделать что-то вроде этого:

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

Вы получите сообщение об ошибке, если попытаетесь создать NumbersOnly, у которого нет перегрузки ValidateType:

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

Ответ 4

Вот как вы это делаете.

Обратите внимание на специализацию шаблона для double, например.. и он не позволит вам вызывать эту функцию с двойным параметром. Хитрость заключается в том, что если вы попытаетесь вывести сумму с типом, который не относится к специализациям 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;
}

Ответ 5

Почему вы хотите ограничить типы в этом случае? Шаблоны позволяют "статическую утиную печать", поэтому все, что разрешено, в соответствии с вашей функцией sum в этом случае должно быть разрешено. В частности, единственной операцией, требуемой для T, является добавление и инициализация на 0, поэтому любой тип, поддерживающий эти две операции, будет работать. Это красота шаблонов.

(Если вы изменили свой инициализатор на T result = T(); или тому подобное, то он будет работать и для чисел, и для строк).

Ответ 7

В самом деле, нет необходимости делать его более строгим. Посмотрите на строковую версию (используя стиль конструктора по умолчанию, рекомендованный Крисом Джеттером-Яном) здесь...

Соблюдайте осторожность при переполнении - вам может потребоваться больший тип, чтобы содержать промежуточные результаты (или результаты вывода). Добро пожаловать в область метапрограммирования, затем:)