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 "";
}
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.
Accumulators is both a library for incremental statistical computation as well as an extensible framework for incremental calculation in general.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With