std::scoped_allocator_adaptor 和一个 class 以及一个使用 std::allocator_arg_t 的构造函数

std::scoped_allocator_adaptor and a class with a constructor using std::allocator_arg_t

我在这里找到一些词http://en.cppreference.com/w/cpp/memory/scoped_allocator_adaptor/construct

if std::uses_allocator<T, inner_allocator_type>::value==true (the type T uses allocators, e.g. it is a container)

and if std::is_constructible<T, std::allocator_arg_t, inner_allocator_type, Args...>::value==true,

then calls

std::allocator_traits<OUTERMOST>::construct( OUTERMOST(*this),
                                             p,
                                             std::allocator_arg,
                                             inner_allocator(),
                                             std::forward<Args>(args)... );

所以,我做一个简单的测试

struct use_arg {
    template <typename Alloc>
    use_arg(std::allocator_arg_t, Alloc &, int i)
        { std::cout << i << " in use_arg()\n"; }
};

namespace std {

template <typename A> struct uses_allocator<use_arg, A>: true_type {};

} // namespace std

void test_scoped()
{
    std::scoped_allocator_adaptor<std::allocator<use_arg>> sa;
    auto p = sa.allocate(1);
    sa.construct(p, 4);
    sa.destroy(p);
    sa.deallocate(p, 1);
}

但是 gcc 和 clang 给我这些错误 https://gist.github.com/anonymous/3e72754a7615162280fb

我也写use_a来代替use_arg。它可以 运行 成功。

struct use_a {
    template <typename Alloc>
    use_a(int i, Alloc &) { std::cout << i << " in use_a()\n"; }
};

是什么导致了这些行为?

问题是,您通过引用收到 Alloc

std::is_constructible<T, std::allocator_arg_t, inner_allocator_type, Args...>::value==true

这里你的情况 inner_allocator 只是 std::scoped_allocator_adaptor<std::allocator<use_arg>> 并且无法转换为 std::scoped_allocator_adaptor<std::allocator<use_arg>>&。您可以只按值接收 Alloc,或按 const-reference.

我认为 libstdc++ 和 libc++ 都在做标准对 OP 示例的要求。

uses_allocator<use_arg, allocator<use_arg>> 为真,但 is_constructible<use_arg, allocator_arg_t, inner_allocator_type, int> 为假,因为 use_arg 不能从右值分配器构造,所以 construct 调用应该是 ill-formed .

但是,我认为这是标准中的一个缺陷。考虑这种类型:

struct use_arg {
  using allocator_type = std::allocator<use_arg>;
  use_arg(allocator_type&&) { }
};

uses_allocatoris_constructible 特征都为真,但调用 scoped_allocator_adaptor::construct(pointer) 将无法编译。

检查 is_constructible<T, inner_allocator_type>(从右值分配器测试构造)然后传递 inner_allocator_type&(这是一个左值)是不一致的,但这就是标准所说的。