简体   繁体   English

为什么boost :: sort会推断出const range&输入类型?

[英]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;

Here is the fix live on Coliru . 这是Coliru上的实时修复程序

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM