How to improve the functionality, exception safeness and other aspects of the following container adaptors?
Allows to write more generic code (not working for, say, <set>
):
#include <utility>
#include <iterator>
#include <type_traits>
template< typename container, bool = std::is_const< std::remove_reference_t< container > >::value >
struct consumable_container;
template< typename container >
struct consumable_container< container, false >
{
consumable_container(container && _container) noexcept
: container_(std::forward< container >(_container))
{ ; }
auto
begin() noexcept
{
return std::make_move_iterator(std::begin(container_));
}
auto
end() noexcept
{
return std::make_move_iterator(std::end(container_));
}
private :
container container_;
};
template< typename container >
struct consumable_container< container, true >
{
static_assert(!std::is_rvalue_reference< container >::value);
consumable_container(container && _container) noexcept
: container_(std::forward< container >(_container))
{ ; }
auto
begin() const noexcept
{
return std::cbegin(container_);
}
auto
end() const noexcept
{
return std::cend(container_);
}
private :
container container_;
};
template< typename container >
consumable_container< container >
move_if_not_const(container && _container) noexcept
{
return std::forward< container >(_container);
}
// some generic code
#include <list>
template< typename container >
auto
transform_to_list(container && _container) noexcept
{
static_assert(std::is_reference< container >::value || !std::is_const< container >::value);
std::list< typename std::remove_reference_t< container >::value_type > list_;
for (auto && value_ : move_if_not_const(std::forward< container >(_container))) {
list_.push_back(std::forward< decltype(value_) >(value_));
}
return list_;
}
// testing data type
#include <iostream>
struct A
{
A() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
~A() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(A const &) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(A &) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A(A &&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
A & operator = (A const &) { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
A & operator = (A &) { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
A & operator = (A &&) { std::cout << __PRETTY_FUNCTION__ << std::endl; return *this; }
};
// testing
#include <deque>
#include <forward_list>
#include <vector>
#include <cstdlib>
int
main()
{
{
std::deque< A > const deque_(1);
std::list< A > ld_ = transform_to_list(deque_);
}
std::cout << std::endl;
{
std::forward_list< A > forward_list_;
forward_list_.push_front(A{});
std::list< A > ls_ = transform_to_list(forward_list_);
}
std::cout << std::endl;
{
std::vector< A > vector_;
vector_.push_back(A{});
std::list< A > lv_ = transform_to_list(std::move(vector_));
}
return EXIT_SUCCESS;
}
Allows to enumerate elements in reverse order:
#include <utility>
#include <iterator>
template< typename container >
struct reversed_container
{
reversed_container(container && _container) noexcept
: container_(std::forward< container >(_container))
{ ; }
auto
begin() noexcept
{
return std::rbegin(container_);
}
auto
end() noexcept
{
return std::rend(container_);
}
private :
container container_;
};
template< typename container >
reversed_container< container >
reverse(container && _container) noexcept
{
return std::forward< container >(_container);
}
// testing
#include <iostream>
#include <vector>
#include <cstdlib>
int
main()
{
std::vector< int > vector_({1, 2, 3, 4, 5});
// using
for (int i : reverse(vector_)) {
std::cout << i << std::endl;
}
return EXIT_SUCCESS;
}
Allows to print list of elements with delimiter (without trailing delimiter):
#include <utility>
#include <iterator>
template< typename container >
struct head_container
{
head_container(container && _container) noexcept
: container_(std::forward< container >(_container))
{ ; }
auto
begin() noexcept
{
return std::begin(container_);
}
auto
end() noexcept
{
auto last = std::end(container_);
if (last == std::begin(container_)) {
return last;
} else {
return std::prev(last);
}
}
private :
container container_;
};
template< typename container >
head_container< container >
head(container && _container) noexcept
{
return std::forward< container >(_container);
}
// testing
#include <iostream>
#include <vector>
#include <cstdlib>
int
main()
{
std::vector< int > vector_({1, 2, 3, 4, 5});
// using
if (!vector_.empty()) {
for (int i : head(vector_)) {
std::cout << i << ", ";
}
std::cout << vector_.back() << std::endl;
}
return EXIT_SUCCESS;
}
Allows to treat first element in special way:
#include <utility>
#include <iterator>
template< typename container >
struct tail_container
{
tail_container(container && _container) noexcept
: container_(std::forward< container >(_container))
{ ; }
auto
begin() noexcept
{
auto first = std::begin(container_);
if (first == std::end(container_)) {
return first;
} else {
return std::next(first);
}
}
auto
end() noexcept
{
return std::end(container_);
}
private :
container container_;
};
template< typename container >
tail_container< container >
tail(container && _container) noexcept
{
return std::forward< container >(_container);
}
// testing
#include <iostream>
#include <vector>
#include <cstdlib>
int
main()
{
std::vector< int > vector_({1, 2, 3, 4, 5});
// using
if (!vector_.empty()) {
for (int i : tail(vector_)) {
vector_.front() += i;
}
std::cout << vector_.front() << std::endl;
}
return EXIT_SUCCESS;
}
transform_to_list()
available via constructor and iterators.reverse()
is available by directly callingrbegin() and
rend()` or using arange
adapter from boost. Yourhead()
and tail is better adapted using an iterator adapter see stackoverflow.com/a/1430892/14065 \$\endgroup\$