Zoom range adapter that does the assembly

I want to write a boost adapter to put an end to the chain of adapters for creating a collection, for example:

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

Usage Method 3.1 I wrote the code below, which works as expected:

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;
}

But if I uncomment one line, I get:

bug C2338: the C ++ standard prohibits containers of const elements because the allocator is poorly formed.

If I make the first parameter operator|be &&, then this works until I uncomment the line filtered()and then get:

error C2825: "R": must be a class or namespace followed by "::"

What is the right way to do this?

+4
1

, . ( . , const, 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; })
    );
+1

Source: https://habr.com/ru/post/1680170/


All Articles