Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::accumulate with a reference?

Trying to 'misuse' std::accumulate for an algorithm (why is it in "numeric" header anyway ? ;) )

template<class Range, class Seperator>
std::string strjoin(Range&& range, Seperator&& seperator) {
    if (std::empty(range)) {
        return "";
    }
    return std::accumulate(std::begin(range) + 1, std::end(range), std::ostringstream{} << *std::begin(range), [seperator](auto&& lhs, auto&& rhs) { return lhs << seperator << rhs; }).str();
}

Compiler explorer

The above doesn't compile and is in a somewhat 'naive' form, but I think it highlights 'the issue'.

Errors from compiler explorer link:

<source>(13): error C2280: 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const std::basic_ostream<char,std::char_traits<char>> &)': attempting to reference a deleted function

C:/data/msvc/14.22.27905/include\ostream(57): note: see declaration of 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream'

C:/data/msvc/14.22.27905/include\ostream(57): note: 'std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const std::basic_ostream<char,std::char_traits<char>> &)': function was explicitly deleted

C:/data/msvc/14.22.27905/include\numeric(72): note: see reference to function template instantiation 'std::basic_ostream<char,std::char_traits<char>> strjoin::<lambda_d85bd1f8d5f8c34784482fe135d50702>::operator ()<std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>,int&>(std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>> &&,int &) const' being compiled

<source>(13): note: see reference to function template instantiation '_Ty std::reduce<std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,_Ostr,strjoin::<lambda_d85bd1f8d5f8c34784482fe135d50702>>(const _InIt,const _InIt,_Ty,_BinOp)' being compiled

        with

        [

            _Ty=std::ostringstream,

            _Ostr=std::ostringstream,

            _InIt=std::_Vector_iterator<std::_Vector_val<std::_Simple_types<int>>>,

            _BinOp=strjoin::<lambda_d85bd1f8d5f8c34784482fe135d50702>

        ]

<source>(19): note: see reference to function template instantiation 'std::string strjoin<std::vector<int,std::allocator<int>>&,const char(&)[4]>(Range,Seperator)' being compiled

        with

        [

            Range=std::vector<int,std::allocator<int>> &,

            Seperator=const char (&)[4]

        ]

C:/data/msvc/14.22.27905/include\numeric(72): error C2679: binary '=': no operator found which takes a right-hand operand of type 'std::basic_ostream<char,std::char_traits<char>>' (or there is no acceptable conversion)

C:/data/msvc/14.22.27905/include\sstream(488): note: could be 'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>> &std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>::operator =(const std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>> &)'

C:/data/msvc/14.22.27905/include\sstream(468): note: or       'std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>> &std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>>::operator =(std::basic_ostringstream<char,std::char_traits<char>,std::allocator<char>> &&)'

C:/data/msvc/14.22.27905/include\numeric(72): note: while trying to match the argument list '(_Ty, std::basic_ostream<char,std::char_traits<char>>)'

        with

        [

            _Ty=std::ostringstream

        ]

Compiler returned: 2

A code snippet for those interested in how to write the algorithm with a plain for loop:

template<class Range, class Seperator>
std::string strjoin(Range&& range, Seperator&& seperator) {
    if (!std::empty(range)) {
        std::ostringstream oss{};
        oss << *std::begin(range);
        for (auto&& e : iter_range(std::begin(range) + 1, std::end(range))) {
            oss << seperator << e;
        }
        return oss.str();
    }
    return "";
}
like image 310
darune Avatar asked Jan 27 '20 13:01

darune


People also ask

What does std :: accumulate do?

std::accumulate() is a built-in function in C++'s Standard Template Library. The function takes in a beginning iterator, an ending iterator, initial value, and (by default) computes the sum of the given initial value and the elements in the given range. The function can also​ be used for left folding.

What is accumulator in C++?

Accumulators is both a library for incremental statistical computation as well as an extensible framework for incremental calculation in general.


1 Answers

std::accumulate requires that the "accumulator" (the third parameter) be CopyAssignable and CopyConstructible. A std::ostringstream is neither, so you cannot use it.

You are going to need to use a different approach like std::for_each, use accumulate, but make the accumulator a std::string that you append to, or some other approach.

like image 101
NathanOliver Avatar answered Oct 17 '22 01:10

NathanOliver