Принуждение функции принимать только определенный набор типов данных

#c #types #sum

#c #типы #сумма

Вопрос:

есть ли какой-либо способ заставить функции принимать только векторы целых чисел (int, unsigned int, uint32_t и т.д.) И только их? я пытаюсь написать простую функцию, которая возвращает сумму всех значений с одинаковым типом возвращаемого значения (поскольку я не могу быть уверен, будет ли значение больше (2 ^ 32 — 1). однако, поскольку у std::vector<T> нее нет cout оператора для всего типа, я не могу этого сделать sum(vector<vector<T> >) , поскольку он вернет vector (игнорируя тот факт, что vector vector не работает). я не хочу перегружать каждый тип для cout чего-либо, потому что мне это не понадобится. я просто хочу, чтобы функция работала, когда T является некоторой формой int (и float, если возможно)

я пытался использовать try/except , но codeblocks улавливает операторы типов, поэтому я не могу скомпилировать, если я выполняю sum(vector <vector <T> >)

 template <typename T>
T sum(std::vector <T> in){
    try{
        T total = 0;
        for(int x = 0; x < in.size(); x  )
            total  = in[x];
        return total;
    }
    catch (int e){
        std::cout << "Error " << e << " has occured." << std::endl;
        exit(e);
    }
}
  

Комментарии:

1. если T это интегральный тип, то невозможно, чтобы в вашем коде был выдан int .

2. я еще не знаком с использованием try / catch

3. Я предлагаю никогда не использовать их, пока вы не узнаете, для чего они предназначены. Как правило, чем меньше их в вашем коде, тем лучше.

4. К вашему сведению — если ваш sum() шаблон создан для типа, для которого T total = 0 недопустимо, то вы получите ошибку компилятора. Ситуации никогда не разрешается задерживаться и проявляться во время выполнения, когда выполняются исключения и блоки try / catch. C не выполняет компиляцию во время выполнения. Отдельно взятие вашего входного вектора по const ссылке предотвращает создание временной копии всего контейнера при каждом вызове функции… Gene иллюстрирует это, но не объясняет и не оправдывает.

Ответ №1:

 template <typename T>
typename std::enable_if<
    std::is_integral<typename std::remove_reference<T>::type>::value,
    T>::type
sum(const std::vector<T>amp; in) { return std::accumulate(in.begin(), in.end(), 0); }
  

Комментарии:

1. Не может иметь std::vector ссылок (не то чтобы это делало ваш код недопустимым).

2. @Luc: правильно, после ввода этих вещей снова и снова это стало почти автоматическим 🙂

Ответ №2:

SFINAE приходит на помощь.

 #include <type_traits>
//#include <tr1/type_traits> // for C  03, use std::tr1::

template<bool, class T = void>
struct enable_if{};

template<class T>
struct enable_if<true,T>{
  typedef T type;
};

template<class T>
typename enable_if<
    std::is_arithmetic<T>::value,
    T
>::type sum(std::vector <T> in){
    T total = 0;
    for(int x = 0; x < in.size(); x  )
        total  = in[x];
    return total;
}
  

Комментарии:

1. оба решения выдают ошибки с error: 'enable_if' in namespace 'std' does not name a type

2. @calccrypto Вы включили <type_traits> так, как это указано в ответе Xeo? Знает ли ваш компилятор C 0x?

3. ДА. я пробовал оба. я также включил c 0x, и он отправляет меня в сумасшедшие места, говоря, что есть ошибки (вероятно, из-за новых правил)

4. calccrypto: трудно диагностировать проблемы C 0x без надлежащей информации о коде и сообщении об ошибке. Избегая C 0x, хотя, вероятно, это доставляет больше хлопот, чем того стоит, если вы еще не используете boost, boost также предоставляет совместимый с C 03 enable_if шаблон и is_arithmetic<> другие тесты, Которые вы могли бы использовать….

5. если вы хотите включить как целочисленную, так и с плавающей запятой, вы можете просто использовать std::is_arithmetic<T>