7

Originato da this argomento CodeReview:std :: is_constructible non dà il risultato corretto

#include <cstddef> 
#include <algorithm> 
#include <iostream> 
#include <type_traits> 
#include <utility> 

template <typename T> 
class aggregate_wrapper : public T { 
private: 
    using base = T; 

public: 
    using aggregate_type = T; 

    template <typename... Ts> 
    aggregate_wrapper(Ts&&... xs) 
     : base{std::forward<Ts>(xs)...} { 
    // nop 
    } 
}; 

struct foo_t { 
    foo_t(int) {} 
}; 

int main() { 
    std::cout << std::is_constructible<foo_t>::value << std::endl; 
    std::cout << std::is_constructible<aggregate_wrapper<foo_t>>::value << std::endl; 
    // aggregate_wrapper<foo_t> v; // won't compile 
} 

Come potrebbe std::is_constructible<aggregate_wrapper<foo_t>>::value essere vero quando aggregate_wrapper<foo_t> v; in realtà non compilare?

+0

Forse stai confondendo mentalmente * costruibile * con * predefinito costruibile *? Un 'aggregate_wrapper ' può certamente essere costruito, ma non tramite 'aggregate_wrapper v;'. –

+0

@ M.M No, 'is_default_constructible ' e 'is_constructible ' (il che significa che 'Args ...' è un pacchetto vuoto) sono equivalenti. –

+0

Non sono sicuro del motivo per cui è stato riaperto; il dup è direttamente sul punto. –

risposta

2

Nello standard C++, nella descrizione is_constructible, c'è questa citazione innocente:

Solo la validità della contesto immediato del [immaginario v] inizializzazione delle variabili è considerato.

E poi una nota che spiega che cosa significa:

La valutazione del inizializzazione può risultare in parte effetti come l'istanza di specializzazioni modello di classe e specializzazioni modello di funzione, il generazione di implicitamente funzioni definite e così via. Tali effetti collaterali non si trovano nel contesto immediato e possono causare l'errata formazione del programma.

La mia interpretazione è che quando si scrive:

aggregate_wrapper<foo_t> v; 

Si utilizza il costruttore di default di aggregate_wrapper, esiste ed è accessibile, così ci riesce, almeno nel contesto immediato. Quindi, il contesto non immediato include il corpo del costruttore e ciò non riesce, ma ciò non modifica il risultato di is_constructible.

+0

Quindi suppongo che 'std :: is_constructible' non sia comunque utile. Preferirei scriverne uno che vada oltre questo contesto immediato. – Lingxi

+0

La vera domanda dovrebbe essere il motivo per cui 'std :: is_constructible' si ferma nel' contesto immediato'? – Lingxi