Skip to main content
added 32 characters in body
Source Link

Allows to write more generic code (not working for, say, <set>):

Allows to write more generic code:

Allows to write more generic code (not working for, say, <set>):

Source Link

Container adaptors

How to improve the functionality, exception safeness and other aspects of the following container adaptors?

Allows to write more generic code:

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