2015-11-12 14 views
9

Ist ein Ausdruck in noexcept Klammern des Spezifizierers an SFINAE während der Überladungsauflösung von Funktionsvorlagen beteiligt?SFINAE und noexcept specifier

Ich möchte einen Wrapper für Aggregate machen und wollen das std::is_constructible Prädikat richtig für sie zu arbeiten:

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

Aber mein Versuch noexcept Betreiber innerhalb noexcept Spezifikation zu verwenden SFINAE zu ermöglichen, ist gescheitert, und das Templat-Konstruktor akzeptiert alles, was ihm übergeben wurde. Wie kann der Konstrukteur eingeschränkt werden?

Es ist vom Standard nicht gestattet, Prädikate von <type_traits> zu spezialisieren. Wie geht man mit c-tors um, die Variant Template Packages und SFINAE generell akzeptieren? Gibt es eine Sackgasse und inhärente Sprachfehler?

+0

Welcher Compiler ist das? – ThomasMcLeod

+0

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

+0

@ThomasMcLeod * g ++ * gibt frühen schweren Fehler (in C-Tor selbst und nicht ein SFINAE). – Orient

Antwort

6

SFINAE einfach findet keine Anwendung auf Ausnahme-Spezifikation s, ob oder ob nicht noexcept Ist Teil von des Funktionstyps.

Siehe den Hinweis in [temp.abziehen]/7:

Die Substitution tritt in allen Typen und Ausdrücke, die in der Funktionstyp und in den Schablonenparameterdeklarationen verwendet werden. Die Ausdrücke enthalten nicht nur konstante Ausdrücke wie diejenigen, die in Array-Grenzen oder als Nicht-Typ-Vorlage Argumente erscheinen, sondern auch allgemeine Ausdrücke (dh nicht konstante Ausdrücke) innerhalb sizeof, decltype und andere Kontexte, die nicht-konstante Ausdrücke erlauben . Die Ersetzung erfolgt in lexikalischer Reihenfolge und wird beendet, wenn eine Bedingung auftritt, die dazu führt, dass der Abzug fehlschlägt. [Hinweis: Die äquivalente Substitution in Ausnahme Spezifikationen wird nur durchgeführt, wenn die exception-Spezifikation instanziert wird, wobei an diesem Punkt ein Programm schlecht gebildet wird, wenn die Substitution zu einem ungültigen Typ oder Ausdruck. - Endnote]

P0012R1 didn't change anything in dieser Hinsicht.

Piotrs Antwort deckt die Fehlerbehebung für Ihren Code ab.

+0

Willst du sagen, 'C++ 17' bringt in dieser Hinsicht nichts Neues? – Orient

+2

@Orient P0012R1 ist das "add exception specifications to type system" Papier, und es hat nichts mit SFINAE auf Ausnahmespezifikationen geändert. Es ist verfrüht zu sagen, C++ 17 wird X nicht tun, wenn wir noch zwei Jahre weg sind. –

2

Ist ein Ausdruck in noexcept Klammern der Spezifizierer in SFINAE bei Überlast Auflösung von Funktionsschablonen teilnehmen?

Es nimmt nicht am Vorlagenabzug teil, weil der noexcept Spezifizierer nicht Teil des Funktionstyps ist.

Die noexcept-Spezifikation ist kein Teil des Funktionstyps. (Bis C++ 17)

Source

Wenn daher Ihr Template-Parameter type abgeleitet wird, ist noexcept nicht Teil des abgeleiteten Typs. Ihr Compiler scheint true für jeden Typ zurückzugeben, weshalb Sie nicht erkennen können, ob es noexcept oder nicht ist; Deshalb wird alles akzeptiert.

Ich lief in das gleiche Problem. Sie können meine Frage/Antwort hier überprüfen:

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

Grundsätzlich Ihre einzige Option für eine C++ 17-konformen Compiler warten ist.

+0

Scheint, dass '-std = gnu ++ 1z' ​​momentan nicht erlaubt, das Erwähnte als Antwort zu verwenden. Auch in 'clang ++' weder in 'g ++'. – Orient

+0

Warum unterscheidet sich 'g ++' s und 'clang ++'s Compilerverhalten? – Orient

+0

@Orient Es hängt davon ab, wie konform sie mit C++ 17 sind, sonst steht Ihnen der 'noexcept' Teil vom abgeleiteten Typ nicht zur Verfügung. – user2296177

4

Wie kann der Konstrukteur eingeschränkt werden?

#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

(oder kürzer):

#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

Ich denke, nicht schleppende Vorlage Parameterpaket ist nicht erlaubt. Können Sie diesen Punkt erläutern? – Orient

+0

In jedem Fall ist es die perfekte Lösung. – Orient

+2

@Orient Es ist erlaubt, wenn es abgeleitet werden kann. Ein Parameterpaket muss am Ende nur für primäre Klassenvorlagen und Aliasvorlagen stehen. –