4

我想编写一个 boost 适配器放在一个适配器链的末尾以创建一个集合,如下所示:

set<string> s = input | filtered(...) | transformed(...) | to_set;

使用方法 3.1我编写了下面的代码,它似乎按预期工作:

namespace detail
{
    struct to_set_forwarder
    {
    };
};

template <class R> inline auto operator|(R& r, detail::to_set_forwarder)
{
    return set<R::value_type>(r.begin(), r.end());
}

template <class R> inline auto operator|(const R& r, detail::to_set_forwarder)
{
    return set<const R::value_type>(r.begin(), r.end());
}

namespace
{
    const auto to_set = detail::to_set_forwarder();
}

void F()
{
    vector<string> input{ "1", "2", "3" };
    auto result = input
        //| boost::adaptors::filtered([](const auto& _) { return true; })
        | to_set;
}

但是如果我取消注释那一行,我会得到:

错误 C2338:C++ 标准禁止 const 元素的容器,因为分配器格式错误。

如果我将第一个参数设置operator|&&,那么直到我取消注释该filtered()行,然后我得到:

错误 C2825:“R”:后跟“::”时必须是类或命名空间

这样做的正确方法是什么?

4

1 回答 1

2

就像它说的那样,标准容器不能存储 const 元素。你也不想(因为无论如何你都存储副本。如果你想要它们 const,你可以制作 container const)。

修复方法是:

template <class R> inline auto operator|(const R& r, detail::to_set_forwarder)
{
    return std::set<typename R::value_type>(r.begin(), r.end());
}

(删除const)。

Live On Coliru

#include <boost/range.hpp>
#include <boost/range/adaptors.hpp>
#include <set>
#include <vector>
#include <iostream>
#include <string>

namespace detail
{
    struct to_set_forwarder
    {
    };
}

template <class R> inline auto operator|(R& r, detail::to_set_forwarder)
{
    return std::set<typename R::value_type>(r.begin(), r.end());
}

template <class R> inline auto operator|(const R& r, detail::to_set_forwarder)
{
    return std::set<typename R::value_type>(r.begin(), r.end());
}

namespace
{
    const auto to_set = detail::to_set_forwarder();
}

void F()
{
    std::vector<std::string> input{ "1", "2", "3", "2" };
    auto result = input
        | boost::adaptors::filtered([](const auto& _) { return true; })
        | to_set;

    for (auto x : result)
        std::cout << x << " ";
}

int main() {
    F();
}

印刷

1 2 3

PS:您缺少typename资格(有时尝试使用 MSVC 以外的其他编译器)

PS:你可以boost::copy_range

auto result = boost::copy_range<std::set<std::string> >(input
    | boost::adaptors::filtered([](const auto& _) { return true; })
    );
于 2017-06-27T07:52:12.447 回答