从标准容器重新绑定和复制分配器

时间:2018-05-08 07:16:29

标签: c++ language-lawyer c++17 allocator

背景

我想创建一个函数,当给定vector V时,会向V中的每个元素返回vector reference_wrapper个VR。

这很简单,但我还希望返回的向量复制反弹分配器,以防原始向量具有(可能是有状态的)自定义分配器。

我想出了下面的MVCE,它编写了godbolt。

问题:

  • 我的理解和实现是否正确,特别是关于重新绑定分配器?
  • 它是否适用于所有符合用户定义的分配器?
  • 如果没有,我错过了什么?

代码:

#include <algorithm>
#include <string>
#include <vector>
#include <functional>
#include <type_traits>

// A class to make my nasty string unmoveable, and therefore expensive
// to sort
struct Nasty
{
    Nasty(std::string s) : value_(std::move(s)) {}
    Nasty(Nasty const&) = default;
    Nasty& operator=(Nasty const&) = default;

    auto value() const -> std::string const& {
        return value_;
    }
    std::string value_;
};

// function object class to deduce types and perform the conversion
template<class V>
struct as_references_op
{
    using vector_type = V;
    using value_type = typename V::value_type;
    static constexpr bool is_const = std::is_const<vector_type>::value;
    using referred_type = std::conditional_t<is_const, std::add_const_t<value_type>, value_type>;

    using allocator_type = typename V::allocator_type;
    using a_traits = std::allocator_traits<allocator_type>;
    using rebound_allocator = typename a_traits::template rebind_traits<referred_type>::allocator_type;

    using result_type = std::vector<std::reference_wrapper<referred_type>, rebound_allocator>;

    result_type operator()(V& v) const
    {
        auto result = result_type(v.begin(), v.end(), v.get_allocator());
        return result;
    }
};

// interface functions    
template<class T, class A>
decltype(auto) as_references(std::vector<T, A> const& v)
{
    auto op = as_references_op<std::vector<T, A> const>();
    return op(v);
}

template<class T, class A>
decltype(auto) as_references(std::vector<T, A>& v)
{
    auto op = as_references_op<std::vector<T, A>>();
    return op(v);
}

// test    
int main()
{
    auto v = std::vector<Nasty> { Nasty("gah"), Nasty("bar"), Nasty("zoo"), Nasty("foo") };

    auto sv = as_references(v);

    auto by_dereferenced_value = [] (auto&& x, auto&& y) {
        return x.get().value() < y.get().value();
    };
    std::sort(begin(sv), end(sv), by_dereferenced_value);
}

0 个答案:

没有答案