[英]Why Does boost::sort deduce a const range& input type?
When I try to pass the result of a nested boost::accumulate
algorithm (where the result is a std::vector
) into boost::sort
, the compiler deduces that the input of boost::sort
is a const std::vector&
even though it correctly deduces the return type of boost::accumulate
to be std::vector
. 当我尝试将嵌套的
boost::accumulate
算法的结果(其中结果为std::vector
)传递给boost::sort
,编译器推断出boost::sort
的输入是const std::vector&
即使它正确推断出boost::accumulate
的返回类型为std::vector
。 Why is that? 这是为什么? The code below does not compile, complaining about
operator=
being undefined for resultT
. 以下代码无法编译,抱怨没有为
resultT
定义operator=
。
#include <boost/range/algorithm/find_if.hpp>
#include <boost/range/algorithm_ext/copy_n.hpp>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/numeric.hpp>
#include <iomanip>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
struct resultT
{
std::string name;
double quantity;
};
auto operator<(const resultT& lhs, const resultT& rhs) -> bool
{
return std::tie(lhs.quantity, lhs.name)
< std::tie(rhs.quantity, rhs.name);
}
auto operator>(const resultT& lhs, const resultT& rhs) -> bool
{
return rhs < lhs;
}
auto operator<<(std::ostream& os, const resultT& row) -> std::ostream&
{
os << row.name << '\t' << std::setprecision(4) << std::fixed << row.quantity;
return os;
}
template<typename T>
auto calculate(const T& in) -> double
{
//a stand-in for real operations on T--not important to the example
return in.second;
}
using resultContainer = std::vector<resultT>;
template<typename QuantityT>
auto add(resultContainer& accumulated, const QuantityT& next) -> resultContainer&
{
auto accumulated_itr{boost::find_if(accumulated, [&next](const resultT& in) -> bool
{
return in.name == next.second.first;
})};
if (accumulated_itr == std::end(accumulated))
{
accumulated.emplace_back(resultT{next.second.first, calculate(next.second)});
}
else
{
accumulated_itr->quantity += calculate(next.second);
}
return accumulated;
}
auto main() -> int
{
using InnerT = std::pair<int, std::pair<std::string, int>>;
using OuterT = std::pair<char, std::pair<std::string, int>>;
auto addInnerOne{[](resultContainer& accumulated, const InnerT& next) { return add<InnerT>(accumulated, next); }};
auto addOuterOne{[](resultContainer& accumulated, const OuterT& next) { return add<OuterT>(accumulated, next); }};
auto InnerOne{std::unordered_multimap<int, std::pair<std::string, int>>
{
{0, {"hi", 1}}
, {1, {"ho", 5}}
, {2, {"hi", 7}}
, {3, {"ho", 7}}
, {4, {"hey", 9}}
, {5, {"fiddle", 11}}
, {6, {"hey", 11}}
, {7, {"ho", 3}}
}};
auto OuterOne{std::unordered_map<char, std::pair<std::string, int>>
{
{'A', {"hi", 1}}
, {'B', {"ho", 5}}
, {'C', {"hi", 7}}
, {'D', {"ho", 7}}
, {'E', {"hey", 9}}
, {'F', {"diddle", 21}}
, {'G', {"hey", 5}}
, {'H', {"ho", 3}}
}};
boost::copy_n(
boost::sort(
boost::accumulate(OuterOne
, boost::accumulate(InnerOne
, resultContainer{}
, addInnerOne)
, addOuterOne)
, std::greater<resultT>())
, 5
, std::ostream_iterator<resultT>(std::cout, "\n"));
return 0;
}
Here you can see the issue live on Coliru . 在这里,您可以在Coliru上实时查看该问题 。
Here is a simple fix that goes around the problem. 这是解决问题的简单解决方案。 I already have this fix--I want to know why I needed this workaround in the first place:
我已经有了此修复程序-我想知道为什么首先需要这种解决方法:
auto quant{ //quant's type is correctly deduced to be std::vector
boost::accumulate(OuterOne
, boost::accumulate(InnerOne
, resultContainer{}
, addInnerOne)
, addOuterOne)};
boost::copy_n(
boost::sort(quant
, std::greater<resultT>())
, 5
, std::ostream_iterator<resultT>(std::cout, "\n"));
return 0;
boost::accumulate
is defined as follows: boost::accumulate
定义如下:
template<
class SinglePassRange,
class Value,
class BinaryOperation
>
Value accumulate(const SinglePassRange& source_rng,
Value init,
BinaryOperation op);
That is, it returns a prvalue of a type deduced for Value
(in your case std::vector<resultT>
), thus it cannot be bound by a non-const lvalue reference. 也就是说,它返回为
Value
推导的类型的prvalue(在您的情况下为std::vector<resultT>
),因此它不能由非常量左值引用绑定。 Given two overloads of boost::sort
: 给定
boost::sort
两个重载:
template<class RandomAccessRange>
RandomAccessRange& sort(RandomAccessRange& rng);
template<class RandomAccessRange>
const RandomAccessRange& sort(const RandomAccessRange& rng);
in both cases RandomAccessRange
is deduced as std::vector<resultT>
, but only the latter is viable for call sort(accumulate(..., vector<resultT>{}, ...))
. 在这两种情况下,
RandomAccessRange
都推导出为std::vector<resultT>
,但是只有后者才可以用于调用sort(accumulate(..., vector<resultT>{}, ...))
。
By first assigning the returned value of boost::accumulate
to variable quant
, an expression involving this name is, in turn, a non-const lvalue, so it is bound by the overload you want. 通过首先将
boost::accumulate
的返回值分配给变量quant
,涉及该名称的表达式反过来是一个非常量左值,因此它受到您想要的重载的约束。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.