c++ - 为什么 boost::sort 推导出一个 const 范围和输入类型?

标签 c++ c++11 boost

当我尝试将嵌套的 boost::accumulate 算法(结果是 std::vector)的结果传递给 boost::sort,编译器推断 boost::sort 的输入是一个 const std::vector&,即使它正确地推断出 的返回类型boost::accumulatestd::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 .

最佳答案

boost::accumulate 定义如下:

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

也就是说,它返回为 Value 推导的类型的纯右值(在您的情况下为 std::vector<resultT> ),因此它不能受非常量左值引用的约束。给定 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 ,包含此名称的表达式又是一个非常量左值,因此它受您想要的重载约束。

关于c++ - 为什么 boost::sort 推导出一个 const 范围和输入类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32805349/

相关文章:

c++ - wxSocket wxWidgets 失败

c++ - 无法将 unsigned int 转换为 unsigned int & (Boost adjacency iterator pointer)

c++ - 我应该为赋值运算符使用左值引用限定符吗?

c++ - 模板参数不明确 : could not deduce template argument

c++ - 使用qt c++检查Xml中是否存在根元素

c++ - 使用用户定义的过滤器/运行时表达式评估来过滤对象

c++ - 这是 GCC 错误吗?使用 union 初始化结构

c++ - lambda 运算符重载?

c++ - 将 vector<wstring> 与 Boost.Pool 分配器一起使用

c++ - 来自一组源节点的 BGL dfs