2015-10-10 4 views
9

Ottengo risultati incoerenti per std::is_constructible<void()>::value. La mia interpretazione dello standard è che dovrebbe essere falso. Tuttavia, Clang, con entrambi libC++ e libstdC++ *, restituisce true. GCC e MSVC danno entrambi false. Quale risultato è corretto?Qual è il risultato corretto di std :: is_constructible <void()> :: value?

Standardese

Ecco la standardese, N4527 [meta.unary.prop]/7:

Dato il seguente dichiarazione di funzione:

template <class T> add_rvalue_reference_t<T> create() noexcept; 

la condizione del predicato per un modello specializzazione is_constructible<T, Args...> deve essere soddisfatta se e solo se la seguente definizione di variabile sarebbe ben formata per alcuni ted variabile t:

T t(create<Args>()...); 

Nota: Questo testo cambiato leggermente da C++ 11 (N3485), dove create era segnato noexcept. Tuttavia, i risultati dei miei test non sono cambiati quando sono stati presi in considerazione.

Test Case

Qui è il mio banco di prova minimo sia del tipo di tratto e la definizione standardese:

#include <type_traits> 

static_assert(std::is_constructible<void()>::value, "assertion fired"); 

template<typename T> 
std::add_rvalue_reference_t<T> create() noexcept; 

template<typename T, typename... Args> 
void foo() { 
    T t(create<Args>()...); 
} 

int main() { 
    foo<void()>(); 
} 

Risultati:

Clang (HEAD, libc++):

  • affermazione statica PASSATO
  • foo<void()> non avete compilato

Clang (HEAD, libstdc++) *:

  • affermazione statico SUPERATO
  • foo<void()> non ha compilare

GCC (HEAD, libstdc++):

  • asserzione statica FALLITO
  • foo<void()> non avete compilato

MSVC (versione 19 via http://webcompiler.cloudapp.net/):

  • affermazione statico FALLITO
  • foo<void()> non avete compilato (richiede commentando l'affermazione statica)

* __GLIBCXX__ non è definito quando Clang viene utilizzato sia con l'opzione -stdlib sia con -stdlib=libstdc++. Non sono sicuro che libstdC++ sia in realtà in uso. Se la mia interpretazione dello standard è corretta, non sono sicuro che si tratti di un bug con Clang o con libC++.

+1

Vedere [LWG 2560] (http://wg21.link/lwg2560) e [Clang bug 25513] (https://llvm.org/bugs/show_bug.cgi?id=25513). –

+0

@ T.C., Grazie! È bello da vedere. – chris

risposta

7

Continua a leggere. Dallo stesso paragrafo:

controllo di accesso viene eseguita come se in un contesto estraneo a T e una delle Args. Viene considerata solo la validità del contesto immediato dell'inizializzazione della variabile . [Nota: La valutazione del inizializzazione può provocare effetti collaterali quali l'istanziazione di template specializzazioni classe e specializzazioni modello di funzione, la generazione di funzioni implicitamente definite, e così via. Tali effetti laterali non sono nel "contesto immediato" e possono provocare l'errato formato del programma . -end nota]

L'asserzione non riesce solo quando il costruttore del modello viene creata un'istanza.Tuttavia, come chiarito nella nota, tale asserzione non è nel contesto immediato della definizione della variabile che è considerata, e quindi non influisce sulla sua "validità". Quindi i compilatori possono considerare valida quella definizione, anche se in realtà si sta tentando di costruire un risultato void() in un programma mal formato.

Si noti che i compilatori sono autorizzati a, invece di avere is_constructible yield false, rifiutano semplicemente il programma originale basato sull'asserzione.

Problemi correlati