2013-06-14 11 views
8

Es gibt eine Technik, die ich manchmal verwenden, wenn template Funktionen überschreiben, das so geht:Leere Variant Packs von Enums - machen sie zwei verschiedene Funktionen?

#include <utility> 
template<int> struct unique_enum { enum class type {}; }; 
template<int index> using UniqueEnum = typename unique_enum<index>::type; 
template<bool b, int index=1> 
using EnableFuncIf = typename std::enable_if< b, UniqueEnum<index> >::type; 
template<bool b, int index=1> 
using DisableFuncIf = EnableFuncIf<!b, -index>; 

// boring traits class: 
template<typename T> 
struct is_int : std::false_type {}; 
template<> 
struct is_int<int> : std::true_type {}; 

#include <iostream> 
// use empty variardic packs to give these two SFINAE functions different signatures: 
template<typename C, EnableFuncIf< is_int<C>::value >...> 
void do_stuff() { 
    std::cout << "int!\n"; 
} 
template<typename C, DisableFuncIf< is_int<C>::value >...> 
void do_stuff() { 
    std::cout << "not int!\n"; 
} 

int main() { 
    do_stuff<int>(); 
    do_stuff<double>(); 
} 

Das unterscheidet do_stuff von do_stuff, denn man nimmt 0 oder mehr UniqueEnum<1> s, und der andere nimmt 0 oder mehr UniqueEnum<-1> s. gcc 4.8 betrachtet diese verschiedenen leeren Pakete als unterschiedlich.

Allerdings, in der neuesten Version von clang ich versuchte, dies schlägt fehl: Es behandelt die Funktion mit 0 UniqueEnum<1> s als die gleiche Funktion wie die 0 UniqueEnum<-1> s.

Es gibt einfache Problemumgehungen, die in clang funktionieren, aber ich frage mich, ob meine obige Technik legal ist - tun zwei Funktionen template s, die sich nur durch leere variardic Parameterpakete unterscheiden, tatsächlich anders?

Antwort

2

Ich denke, GCC hat Recht, und Ihre Technik ist richtig. Da das Argument type für C explizit angegeben wird, ist die Frage, ob:

a. Substitution von C überall sonst in der Funktionsschablonen-Signatur passiert zuerst, und dann wird Typabzug durchgeführt (was zu einem Substitutionsfehler führen sollte); oder

b. Typabzug wird zuerst ausgeführt, und dann wird eine Ersetzung durchgeführt (was nicht zu einem Substitutionsfehler führen würde, weil das entsprechende Argumentpaket leer wäre und somit keine Ersetzung durchzuführen wäre).

Es scheint, dass GCC (1) annimmt, während Clang (2) annimmt. Paragraph 14.8.2/2 der C++ 11-Standard spezifiziert:

Wenn eine explizite Vorlage Argumentliste angegeben ist, muss die Vorlage mit der Argumente Vorlage Parameterliste kompatibel sein und in einem gültigen Funktionstyp führen darf wie unten beschrieben; sonst type Abzug schlägt fehl. Speziell werden die folgenden Schritte durchgeführt, wenn eine explizit angegebene Vorlage Argumentliste in Bezug auf eine gegebene Funktion Vorlage Auswertung:

- das angegebene Vorlage Argument die Template-Parameter in Art übereinstimmen muß (dh Typ, nicht-Typ , Vorlage). Es darf nicht mehr Argumente als Parameter geben, es sei denn, mindestens ein Parameter ist ein Template-Parameterpaket, und für jeden Nicht-Pack-Parameter muss ein Argument vorhanden sein. Andernfalls schlägt der Typabzug fehl.

- Nicht-Typ Argumente der Typen der entsprechenden nicht-Typ Template-Parameter übereinstimmen muss, oder muss zu den Typen der entsprechenden nicht-Typ-Parameter umgewandelt werden, wie in 14.3.2 angegeben, sonst Typ Abzug versagt.

- Die angegebenen Vorlagenargumentwerte werden für die entsprechenden Vorlagenparameter wie unter angegeben.

Der folgende Absatz sagt dann:

Nach dieser Substitution durchgeführt wird, beschrieben die Funktionsparameter Typ Anpassungen in 8.3.5 durchgeführt werden. [...]

Außerdem Absatz 14.8.2/5 angibt:

Der erhaltene substituierte und eingestellt Funktionsart wird als Typ der Funktion Template verwendet für eine Vorlage Argument Abzug . [...]

Schließlich Absatz 14.8.2/6 geht wie folgt:

An bestimmten Punkten im Abzug Prozessvorlage Argumente ist es notwendig, einen Funktionstyp zu tragen, dass Gebrauch macht der Template-Parameter und ersetzen Sie diese Template-Parameter mit der entsprechenden Vorlage Argumente. Dies erfolgt am Anfang der Vorlage Argumentabzug, wenn alle explizit angegebenen Vorlage Argumente in den Funktionstyp ersetzt werden, und wieder am Ende der Vorlage Argumentabzug , wenn alle Vorlage Argumente, die abgeleitet oder von Standardargumenten erhalten ersetzt wurden .

Dies alles scheint zu implizieren, dass die erste Substitution durchgeführt wird, dann Vorlage Argumentabzug. Daher sollte in beiden Fällen ein Substitutionsfehler auftreten, und eine der beiden Vorlagen sollte aus der Überladungsgruppe verworfen werden.

Leider scheint es keine klare Spezifikation darüber zu geben, wie das Verhalten aussehen sollte, wenn Templates-Argumente abgeleitet und nicht explizit angegeben werden.

+0

Gilt dies nur, wenn wir das Argument explizit angeben und es nicht ableiten? (Hätte ich die Funktion "T const &" nehmen lassen, dann "7" daran übergeben, wäre der Trick nicht mehr legal?) – Yakk

+0

@Yakk: In diesem Fall bin ich mir nicht ganz sicher, aber ich habe gelesen durch die ganze 14.8.2 mehrere Male und es scheint mir der Standard nicht angibt, was das Verhalten sein sollte –

Verwandte Themen