Я хочу написать повышающий адаптер, чтобы поместить в конец цепочки адаптеров для создания коллекции, например:
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 ++ запрещает контейнеры с константными элементами, потому что распределитель неправильно сформирован.
Если я сделаю первый параметр для operator|
быть &&
тогда это работает, пока я не раскомментирую filtered()
линия, а затем я получаю:
ошибка C2825: «R»: должен быть класс или пространство имен, после которого следует «::»
Какой правильный способ сделать это?
Как говорится, стандартные контейнеры не могут хранить константные элементы. И вы не хотите (потому что вы храните копии в любом случае. Если вы хотите, чтобы они были постоянными, вы можете сделать контейнер 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
).
#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; })
);
Других решений пока нет …