2015-11-12 23 views
9

Un'espressione tra parentesi con identificatori noexcept partecipa a SFINAE durante la risoluzione di sovraccarico dei modelli di funzione?SFINAE e identificatore noex

Voglio fare un wrapper per aggregati e vogliono il predicato std::is_constructible funzioni correttamente per esso:

template< typename type > 
struct embrace 
    : type 
{ 

    template< typename ...arguments > 
    embrace(arguments &&... _arguments) noexcept(noexcept(type{std::forward<arguments>(_arguments)...})) 
     : type{std::forward<arguments>(_arguments)...} // braces 
    { ; } 

}; 

int 
main() 
{ 
    struct S { int i; double j; }; // aggregate 
    using E = embrace<S>; 
    E b(1, 1.0); // "parentheses"-constructible => can be used as usual types 
    b.i = 1; b.j = 2.0; // accessible 
    static_assert(std::is_constructible< E, int, double >{}); 
    static_assert(std::is_constructible< E, struct B >{}); // want hard error here 
    return EXIT_SUCCESS; 
} 

Ma il mio tentativo di utilizzare noexcept operatore all'interno noexcept specifica per abilitare SFINAE è fallito, e il costruttore su modelli accetta tutto ciò che è passato ad esso. Come può essere limitato il costruttore?

Non è consentito dallo Standard specializzare alcun predicato da <type_traits>. Come gestire i c-tor che accettano i pacchetti di parametri modello variadic e SFINAE in generale? C'è un impasse e un difetto linguistico intrinseco?

+0

Che compilatore è questo? – ThomasMcLeod

+0

@ThomasMcLeod [clang 3.7] (http://coliru.stacked-crooked.com/a/46c26922bef7a4f7) – Orient

+0

@ThomasMcLeod * g ++ * restituisce un errore grave all'inizio (nel c-tor stesso e non in un SFINAE). – Orient

risposta

6

SFINAE semplicemente non è dovuta per specifica delle eccezioni s, sia noexcept o no è parte del tipo di funzione.

Vedere la nota in [temp.dedurre]/7:

La sostituzione avviene in tutti i tipi e le espressioni che sono utilizzati nella il tipo di funzione e dichiarazioni di parametri del modello. Le espressioni includono non solo espressioni costanti come quelle che compaiono nei limiti di matrice o come argomenti del modello non tipografico ma anche espressioni generali (ad esempio espressioni non costanti) all'interno di sizeof, decltype e altri contesti che consentono espressioni non costanti . La sostituzione procede in ordine lessicale e si interrompe quando si verifica una condizione in cui causa la deduzione. [Nota : L'equivalente sostituzione nelle specifiche di eccezione viene effettuata solo quando la specifica delle eccezioni viene creata un'istanza, a quel punto un programma è mal formata se i risultati di sostituzione di un tipo non valido o espressione. - nota end]

P0012R1 didn't change anything a questo riguardo.

La risposta di Piotr copre la correzione del codice.

+0

Vuoi dire che 'C++ 17' non porterà qualcosa di nuovo a questo riguardo? – Orient

+2

@Orient P0012R1 è la carta "aggiungi specifiche dell'eccezione per digitare il sistema" e non ha modificato nulla con SFINAE sulle specifiche delle eccezioni. È prematuro dire che C++ 17 non farà X quando mancano ancora due anni. –

2

Un'espressione tra parentesi di un identificatore noxcept partecipa a SFINAE durante la risoluzione di sovraccarico dei modelli di funzione?

Non partecipa alla deduzione modello poiché l'identificatore noexcept non fa parte del tipo di una funzione.

La specifica no -cept non fa parte del tipo di funzione. (Fino C++ 17)

Source

Pertanto, quando il parametro di template type si deduce, noexcept non è parte del tipo dedotta. Il tuo compilatore sembra restituire true per qualsiasi tipo, motivo per cui non sei in grado di rilevare se è noexcept o no; è per questo che tutto è accettato.

Mi sono imbattuto nello stesso problema. È possibile controllare la mia domanda/risposta qui:

How can I detect whether a template argument is a noexcept function?

In sostanza, l'unica opzione è quella di aspettare un C++ 17 compilatore compatibile.

+0

Sembra che '-std = gnu ++ 1z' ​​al momento non consenta di usare la risposta citata. Né in 'clang ++' nemmeno in 'g ++'. – Orient

+0

Perché il comportamento dei compilatori 'g ++' e 'clang ++' 'differisce? – Orient

+0

@Orient Dipende da quanto sono compatibili con C++ 17, altrimenti la parte 'noexcept' non sarà disponibile per il tipo dedotto. – user2296177

4

Come può essere limitato il costruttore?

#include <utility> 

template <typename type> 
struct embrace : type 
{ 
    template <typename... arguments 
      , typename = decltype(type{std::declval<arguments>()...})> 
    embrace(arguments&&... _arguments) 
     noexcept(noexcept(type{std::forward<arguments>(_arguments)...})) 
     : type{std::forward<arguments>(_arguments)...} 
    { 
    } 
}; 

DEMO

(o più breve):

#include <utility> 

template <typename type> 
struct embrace : type 
{ 
    template <typename... arguments 
      , bool NoExcept = noexcept(type{std::declval<arguments>()...})> 
    constexpr 
    embrace(arguments&&... _arguments) 
     noexcept(NoExcept) 
     : type{std::forward<arguments>(_arguments)...} 
    { 
    } 
}; 

DEMO 2

+0

Penso che il pacchetto parametri template non-finali non sia permesso. Puoi chiarire questo punto? – Orient

+0

In entrambi i casi è la soluzione perfetta. – Orient

+2

@Orient È consentito se è possibile dedurre. Un pacchetto di parametri deve essere alla fine solo per modelli di classe primaria e modelli alias –