Ответ 1
Проверяя один из недавних черновиков Post С++ 11 (N3337.pdf), мы видим, что эффект std:: accumulate определяется как
Вычисляет его результат путем инициализации аккумулятора acc с начальным значением init, а затем изменяет его с помощью acc = acc + * я или acc = binary_op (acc, * i) для каждого итератора я в диапазоне [первый, последний] в порядке.
Итак, стандарт фактически запрещает реализации, которые используют std:: move для старого значения аккумулятора следующим образом:
template <class InputIterator, class T, class BinOp>
T accumulate (InputIterator first, InputIterator last, T init, BinOp binop)
{
while (first!=last) {
init = binop(std::move(init), *first);
++first;
}
return init;
}
что является неудачным в вашем случае.
Вариант (1): Внедрите это управление движением, накапливайте себя.
Опция (2): продолжайте использовать функтор, например
struct mutating_string_adder {
string operator()(string const& a, string const& b) const {return a+b;}
string operator()(string & a, string const& b) const {a += b; return std::move(a);}
string operator()(string && a, string const& b) const {a += b; return std::move(a);}
};
Обратите внимание, что здесь я не использовал типы возвращаемых ссылок rvalue. Это преднамеренно, так как может избежать оборванных опорных проблем, например, в случае, когда выбрана последняя перегрузка, и "а" инициализируется для обращения к временному объекту. Все операторы + перегрузки для строк также намеренно возвращаются по значению.
Кроме того, вы можете использовать std:: copy в сочетании с std:: stringstream и итератором выходного потока.
Добавление: Альтернативный mutating_string_adder
с некоторой частичной совершенной пересылкой:
struct mutating_string_adder {
template<class T, class U>
std::string operator()(T && a, U && b) const {
return std::move(a) + std::forward<U>(b);
}
};