2016-01-15 14 views
5

Trovo alcune parole qui http://en.cppreference.com/w/cpp/memory/scoped_allocator_adaptor/constructstd :: scoped_allocator_adaptor e una classe con un costruttore utilizza std :: allocator_arg_t

se std::uses_allocator<T, inner_allocator_type>::value==true (il tipo T utilizza ripartitori, ad esempio, si tratta di un contenitore)

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

poi chiama

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

Quindi, faccio un semplice test

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

ma gcc e clang mi danno questi errori https://gist.github.com/anonymous/3e72754a7615162280fb

scrivo anche use_a per sostituire use_arg. Potrebbe funzionare correttamente.

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

Cosa fa accadere questi comportamenti?

risposta

3

Penso che sia libstdC++ che libC++ stiano facendo esattamente ciò che lo standard richiede per l'esempio dell'OP.

uses_allocator<use_arg, allocator<use_arg>> è vero, ma è falso perché is_constructible<use_arg, allocator_arg_t, inner_allocator_type, int>use_arg non è costruibile da un allocatore rvalue, quindi la chiamata construct dovrebbe essere mal formati.

Tuttavia, penso che sia un difetto nello standard. Considerate questo tipo:

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

I uses_allocator e is_constructible tratti sono entrambe vere, ma chiede a scoped_allocator_adaptor::construct(pointer) non riuscirà a compilare.

Non è coerente controllare is_constructible<T, inner_allocator_type> (che verifica la costruzione da un rovalue allocator), ma poi passare inner_allocator_type& (che è un lvalue), ma è quello che dice lo standard.

1

Il problema è che si riceve Alloc come riferimento.

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

qui nel vostro caso inner_allocator è solo std::scoped_allocator_adaptor<std::allocator<use_arg>> e non possono essere convertiti in std::scoped_allocator_adaptor<std::allocator<use_arg>>&. È possibile ricevere semplicemente Alloc in base al valore o tramite const-reference.

+0

Che dire di 'std :: is_constructible >> :: value'? È anche 'falso', ma potrebbe costruire. – linux40

+0

@ linux40 che sembra un bug, dato che ad esempio in clang, non esiste questo controllo, solo il valore uses_allocator :: è selezionato. – ForEveR

+0

c'è anche un solo controllo in gcc anche. – ForEveR