【发布时间】:2020-01-27 13:28:00
【问题描述】:
试图为算法“滥用”std::accumulate(为什么它仍然在“数字”标头中?;))
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();
}
以上内容无法编译并且有点“幼稚”的形式,但我认为它突出了“问题”。
来自编译器资源管理器链接的错误:
<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
对于那些对如何使用普通 for 循环编写算法感兴趣的人的代码 sn-p:
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 "";
}
【问题讨论】:
-
如果你看到例如this
std::accumulatereference 你会看到init参数是按值 获取的,这意味着该值需要是可复制的。而且流是不可复制的。 -
@Someprogrammerdude 我已经知道一种解决方案是使用
std::ref() -
不知道自己到底想做什么,但请不要试图变得“聪明”。 “聪明”的解决方案往往是不可读和不可维护的。 The Daily WTF 充满了“聪明”的解决方案。只是不要成为代码最终出现在这样一个网站上的那个人。
-
@Someprogrammerdude 说实话,使用
std::ref对我来说是最后一滴(我认为在同一行代码中发挥了太多机制),这就是为什么我恢复到普通的for 循环并在此处发布。
标签: c++ algorithm templates c++17