Recently I wrote a back_inserter with the same interface as the std::back_inserter just for supporting several containers in the constructor and doing push_back for each. The solution needs C++17. Please give me some feedback! Thanks.
#include <iterator>
#include <tuple>
namespace stx {
template <class Container, class... Containers>
class back_insert_iterator
{
public:
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
using iterator_category = std::output_iterator_tag;
explicit back_insert_iterator(Container& container, Containers&... containers) : containers(container, containers...) {
}
back_insert_iterator& operator=(const typename Container::value_type& value) {
std::apply([&](auto&... container) { ((container.push_back(value)), ...); }, containers);
return *this;
}
back_insert_iterator& operator=(typename Container::value_type&& value) {
std::apply([&](auto&... container) { ((container.push_back(std::move(value))), ...); }, containers);
return *this;
}
back_insert_iterator& operator*() {
return *this;
}
back_insert_iterator& operator++() {
return *this;
}
back_insert_iterator& operator++(int) {
return *this;
}
private:
std::tuple<Container&, Containers&...> containers;
};
template <class Container, class... Containers>
auto back_inserter(Container& container, Containers&... containers) {
return back_insert_iterator<Container, Containers...>(container, containers...);
}
}
And you can use it like this:
#include <iostream>
#include <vector>
auto main() -> int {
const auto numbers = std::vector<int>{ 1, 2, 3, 4, 5 };
std::vector<int> copy1, copy2;
std::copy(numbers.begin(), numbers.end(), stx::back_inserter(copy1, copy2));
std::cout << "(numbers == copy1) = " << std::boolalpha << (numbers == copy1) << '\n';
std::cout << "(numbers == copy2) = " << std::boolalpha << (numbers == copy2) << '\n';
};
A front_inserter would of course look similar, just calling push_front instead. Some specific additional questions:
- does the operator= method with the r-value work as intended or do I need to pass the value differently to the lambda?
- do I need an extra static_assert to check that each Container supports the same value_type or at least some that are convertible to avoid overloading the user with template errors in case they are different?
- is there another solution where I could let the user provide and optional argument for execution policy, for example std::execution::par
- the original std::back_inserter saves the container as pointer - is there any advantage versus my inserter which saves them per reference?
(container.push_back(std::move(value))), ...)
: movingvalue
's content several times is a bad idea. After the first move,value
's state is valid but unspecified. It doesn't make a difference in you test because moving anint
is equivalent to copying it, sinceint
s as all built-in types don't have move semantics. But try it withstd::string
s, for instance, and you'll see a difference \$\endgroup\$