2015-12-02 3 views
3

Скажите, что я хочу предоставить элементарные арифметические операции operator+= и operator+ для std::vector для добавления элементов вектора по элементам. Часто я вижу operator+ реализуется в терминах operator+= так:Арифметические операции над векторами

#include <algorithm> 
#include <vector> 

template<class Type> 
std::vector<Type> & operator+=(std::vector<Type> &x, const std::vector<Type> &y) { 
    // Checks for equal size of x and y omitted here... 
    std::transform(std::begin(x), std::end(x), std::begin(y), std::begin(x), std::plus<Type>()); 
    return x; 
} 

template<class Type> 
std::vector<Type> operator+(std::vector<Type> x, const std::vector<Type> &y) { 
    // Checks for equal size of x and y omitted here... 
    return x += y; 
} 

int main() { 
    std::vector<double> v0{1.0, 2.0, 3.0}; 
    auto v1 = v0; 

    auto v2 = v0; 
    v2 += v0; // yields [2, 4, 6] 

    auto v3 = v0 + v1; // yields [2, 4, 6] 

    return 0; 
} 

С точки зрения производительности, я думаю

template<class Type> 
std::vector<Type> operator+(const std::vector<Type> &x, const std::vector<Type> &y) { 
    // Checks for equal size of x and y omitted here... 
    std::vector<Type> result; 
    result.reserve(x.size()); 
    std::transform(std::begin(x), std::end(x), std::begin(y), std::back_inserter(result), std::plus<Type>()); 
    return result; 
} 

является более эффективным, поскольку он позволяет избежать инициализации копию первого аргумента при вводе функция помещает результат непосредственно в неинициализированный блок памяти. Действительно ли стоит реализовать вторую версию или я могу предположить, что компилятор будет оптимизировать в любом случае? Кроме того, я считаю, что второй вариант менее общий, чем первый. Представьте себе, что-то вроде

#include <array> 
#include <type_traits> 

template<class Container, class Enable = void> 
struct IsSequenceContainer: public std::false_type { 
}; 

template<> 
template<class Type, std::size_t size> 
struct IsSequenceContainer<std::array<Type, size> >: public std::true_type { 
}; 

template<> 
template<class Type, class Allocator> 
struct IsSequenceContainer<std::vector<Type, Allocator> >: public std::true_type { 
}; 

// Use the following operations for std::array and std::vector 
template<class Container> 
typename std::enable_if<IsSequenceContainer<Container>::value, Container>::type operator+(Container x, const Container &y) { 
    return x += y; 
} 
+0

Будьте осторожны, если вы обеспечиваете добавление элементов для векторов - убедитесь, что 'operator +' не ошибочно принимается за оператор конкатенации ... –

+0

Существует также [std :: valarray] (http: //en.cppreference. com/w/cpp/numeric/valarray), но он не поддерживает стирание, вставку и т. д. – melak47

+0

@ melak47 Мне известно о 'std :: valarray', но я бы предпочел' std :: vector' над 'std: : valarray', см. [this] (http://stackoverflow.com/questions/1602451) сообщение, например. – Marcel

ответ

3

Как и все выступления, связанные: профиля программы, чтобы увидеть, что происходит.

Мое предположение заключается в том, что компилятор не будет оптимизировать код полностью - и это, вероятно, никогда не имеет значения. Единственный способ узнать наверняка - попробовать.

Реализация + с точки зрения += имеет то преимущество, что две операции, как известно, эквивалентны. Это делает менее вероятным возникновение ошибки. Вы должны убедиться, что ваша оптимизация необходима, прежде чем отказаться от этого преимущества. Идиомы C++ обычно становятся идиомами по уважительным причинам.

1

Вы имели в виду std::valarray? Он уже обеспечивает те операции, которые вам нужны, и вы можете воспользоваться SIMD. Это может быть производительность ++ бесплатно.