为什么boost :: sort推导出一个const范围&输入类型?

时间:2015-09-27 06:53:38

标签: c++ c++11 boost

当我尝试将嵌套boost::accumulate算法的结果(结果为std::vector)传递给boost::sort时,编译器推断出boost::sort的输入是const std::vector&,即使它正确推断boost::accumulate的返回类型为std::vector。这是为什么?下面的代码无法编译,抱怨operator=未定义resultT

#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

这是一个解决问题的简单修复方法。我已经有了这个修复 - 我想知道为什么我首先需要这个解决方法:

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;

Here is the fix live on Coliru

1 个答案:

答案 0 :(得分:1)

boost::accumulate定义如下:

template<
    class SinglePassRange,
    class Value,
    class BinaryOperation
    >
Value accumulate(const SinglePassRange& source_rng,
                 Value init,
                 BinaryOperation op);

也就是说,它返回一个为Value推导出的类型的prvalue(在你的情况下是std::vector<resultT>),因此它不能被非const左值引用绑定。鉴于boost::sort的两个重载:

template<class RandomAccessRange>
RandomAccessRange& sort(RandomAccessRange& rng);

template<class RandomAccessRange>
const RandomAccessRange& sort(const RandomAccessRange& rng);

在这两种情况下RandomAccessRange被推断为std::vector<resultT>,但只有后者才适用于sort(accumulate(..., vector<resultT>{}, ...))

首先将boost::accumulate的返回值赋给变量quant,涉及此名称的表达式又是非常量左值,因此它受到所需重载的约束。 / p>