2013-06-14 17 views
8

Jest to technika czasami używać podczas nadrzędnymi template funkcje, które idzie tak:Puste pakiety zmienne wyliczeń - czy czynią dwie funkcje różnymi?

#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>(); 
} 

To odróżnia do_stuff z do_stuff, ponieważ weźmie 0 lub więcej UniqueEnum<1> s, a druga zajmuje 0 lub więcej UniqueEnum<-1> s. gcc 4.8 uważa te różne puste pakiety za odrębne.

Jednak w najnowszej wersji języka próbowałem, to się nie udaje: traktuje funkcję z 0 UniqueEnum<1> s jako taką samą jak funkcja z 0 UniqueEnum<-1> s.

Istnieją proste obejścia, które działają w szczęściu, ale zastanawiam się, czy moja powyższa technika jest zgodna z prawem - czy dwie funkcje różnią się tylko pustymi pakietami parametrów o różnych parametrach?

Odpowiedz

2

Myślę, że GCC ma rację, a twoja technika jest prawidłowa. Zasadniczo, ponieważ argument typu dla C jest określony jawnie, pytanie brzmi: czy:

a. podstawienie C wszędzie indziej w podpisie szablonu funkcji występuje najpierw, a następnie wykonuje się dedukcję (co powinno skutkować niepowodzeniem substytucji); lub

b. najpierw dokonywana jest dedukcja typu, a następnie dokonywane jest podstawienie (co nie skutkowałoby niepowodzeniem substytucji, ponieważ odpowiadający pakiet argumentów byłby pusty, a zatem nie byłoby podstawienia do wykonania).

Wygląda na to, że GCC przyjmuje (1), podczas gdy Clang przyjmuje (2). Pkt 14.8.2/2 o C++ 11 Norma określa:

Gdy lista jawne szablon argument podano argumenty Szablon musi być zgodna z listą parametrów szablonu i musi prowadzić do ważnej funkcji typu Jak opisano poniżej; w przeciwnym razie można odliczyć odliczenie . Konkretnie następujące kroki są wykonywane przy ocenie listę wyraźnie określony szablon argumentów w odniesieniu do funkcji danego szablonu:

- Określony argumenty szablonu musi dopasować parametry szablonu w naturze (czyli typu non-type , szablon). Nie może być więcej argumentów niż parametrów, chyba że przynajmniej jeden parametr jest pakietem parametrów szablonu, a dla każdego parametru poza pakietem będzie istnieć argument. W przeciwnym razie odliczanie typu kończy się niepowodzeniem.

- argumenty dla typu muszą być zgodne typy odpowiednich parametrów szablonu non-Type, lub musi być wymienialna do rodzajów odpowiednich parametrów dla typu określonych w 14.3.2, inaczej typu odliczenie nie powiedzie się.

- Podane wartości argumentów szablonu zastępują odpowiednie parametry szablonu jako określone poniżej.

dodaje się ustęp potem mówi:

Po tym podstawienie jest wykonywana, korekty typ parametru funkcji opisanych w 8.3.5 są wykonywane. [...]

Ponadto § 14.8.2/5 określa:

Uzyskane podstawione i regulować działanie typu stosowany jest jako typ matrycy funkcyjnych szablon argumentu odjęciu . [...]

Wreszcie pkt 14.8.2/6 jest następujący:

w pewnych momentach procesu odliczenia szablon argumentu jest to niezbędne do podjęcia typu funkcji, które sprawia, że ​​korzystanie parametrów szablonów i zastąpienie tych parametrów szablonów odpowiednimi argumentami szablonu . Odbywa się to na początku odliczania argumentu w szablonie, gdy jakiekolwiek jawnie podane argumenty szablonu są podstawione w typ funkcji, i ponownie na końcu odjęcia odliczenia argumentu szablonu, gdy zostaną odrzucone jakiekolwiek argumenty szablonu, które zostały wyprowadzone lub uzyskane z domyślnych argumentów .

Wszystko to zdaje się sugerować, że wykonywane jest pierwsze zastąpienie, a następnie odrzucenie argumentu szablonu. Dlatego też w obu przypadkach powinna wystąpić awaria podstawienia, a jeden z dwóch szablonów powinien zostać usunięty ze zbioru przeciążeniowego.

Niestety, wydaje się, że nie ma jasnej specyfikacji tego, jakie zachowanie powinno mieć miejsce, gdy argumenty szablonów są wyprowadzane, a nie są jawnie określone.

+0

Czy ma to zastosowanie tylko wtedy, gdy wyraźnie podamy argument, a nie wywnioskujemy? (Czy, gdybym uczynił funkcję wziąć 'T const &', a następnie przeszedłbym '7', czy sztuczka nie byłaby już legalna?) – Yakk

+0

@Yakk: W takim przypadku nie jestem do końca pewien, ale przeczytałem przez cały 14.8.2 kilka razy i wydaje mi się, że Standard nie określa, jakie zachowanie powinno być –