G++ i clang++ różne zachowania z integralnym parametrem szablonu
Mam następujący kod C++11.
#include <type_traits>
using IntType = unsigned long long;
template <IntType N> struct Int {};
template <class T>
struct is_int : std::false_type {};
template <long long N>
struct is_int<Int<N>> : std::true_type {};
int main()
{
static_assert (is_int<Int<0>>::value, "");
return 0;
}
Clang++ 3.3 kompiluje kod, ale w g++ 4.8.2 twierdzenie statyczne nie powiodło się
$ g++ -std=c++11 main.cpp
main.cpp: In function ‘int main()’:
main.cpp:15:5: error: static assertion failed:
static_assert (is_int<Int<0>>::value, "");
^
$
Problem jest spowodowany przez różne integralne parametry szablonu. Który kompilator ma rację w tym przypadku?
2 answers
Niespodzianka
To subtelny pluskwa, głęboko zakopana w normie. Problem polega na tym, że w prawie wszystkich przypadkach argumenty nie będące typem szablonu mogą być przekonwertowane na typ parametru szablonu . Na przykład wyrażenieInt<0>
ma int
dosłowny argument wartości 0
, który jest konwertowany na typ unsigned long long
parametru szablonu N
.
14.8.2 szablon argument dedukcja [temp.
-- Non-type arguments must match the types of the corresponding non-type parametry szablonu, lub muszą być zamieniane na typy odpowiednie parametry inne niż typ określone w pkt 14.3.2, w przeciwnym razie odliczenie typu nie powiodło się.
Ponieważ szablon klasy is_int<T>
ma częściową specjalizację, musimy spojrzeć na
14.5.5.1 dopasowanie szablonu klasy specjalizacje cząstkowe [temp.klasy.spec.mecz]
1 gdy Klasa szablon jest używany w kontekście wymagającym instancjacji klasy, konieczne jest ustalenie, czy instancjację należy wygenerować za pomocą szablonu podstawowego lub jednego z częściowe specjalizacje. odbywa się to poprzez dopasowanie szablonu argumenty specjalizacji szablonu klasy z szablonem lista argumentów częściowych specjalizacji .
2 częściowa specjalizacja pasuje do danego argumentu szablonu lista jeśli szablon argumenty częściowej specjalizacji mogą być wyprowadzony z rzeczywistej listy argumentów szablonu (14.8.2).
Wydaje się więc, że możemy przejść do wcześniejszego cytatu z 14.8.2 / 2 2nd bullet i dopasować drugą specjalizację (chociaż w tym przypadku trzeba by zagrać jeszcze bardziej skomplikowaną grę o rozdzielczości przeciążenia).
Uchwała
Okazuje się jednak (jak wspomniał @DyP w komentarzach), że kolejna klauzula w standardzie zastępuje to:
14.8.2.5 wyprowadzenie argumentów szablonu z typu [temp.odlicz.Typ]
17 jeśli w deklaracji szablonu funkcji o nie-typie template-parametr, nie-typowy templateparametr jest używany w wyrażenie w parametrze funkcji-list i, jeśli odpowiadający szablon-argument jest wyprowadzany, typ szablonu-argument powinien odpowiadać typ szablonu-parametr dokładnie , z tym że a szablon-argument wyprowadzona z wiązania tablicy może być dowolnej całki Typ. [ Przykład:
template<int i> class A { / ... / };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
Wynik jest taki, że częściowa specjalizacja is_int
nie może zostać wydedukowana, ponieważ nie przyjmuje dokładnie tego samego typu (unsigned long long
vs long long
) jako formalny parametr szablonu Int
.
Możesz rozwiązać ten problem, podając parametr szablonu non-type N
w częściowej specjalizacji is_int
ten sam typ, co parametr non-type N
w głównym szablonie Int
.
template <IntType N>
// ^^^^^^^^
struct is_int<Int<N>> : std::true_type {};
Przykład Na Żywo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-29 07:49:48
Clang jest niekonsekwentny. ponieważ akceptuje Twój kod , oczekuję, że następujący kod musi wyjść f(Int<long long>)
zamiast f(T)
:
using IntType = unsigned long long;
template <IntType N> struct Int {};
template<typename T>
void f(T) { std::cout << "f(T)" << std::endl; }
template<long long N>
void f(Int<N>) { std::cout << "f(Int<long long>)" << std::endl; }
int main()
{
f(Int<0>{});
}
Ale o dziwo, wychodzi to ( demo online):
f(T)
, które pokazuje Int<0>
nie pasuje do drugiego przeciążenia, które przyjmuje argument jako Int<N>
. Jeśli tak, to dlaczego pasuje do Int<N>
, gdy jest używany jako argument szablonu do szablonu klasy (w Twoim przypadku)?
Mój wniosek:
- jeśli Clang jest poprawny w moim przypadku , to jest niepoprawny w Twoim przypadku .
- jeśli Clang jest poprawny w Twojej sprawie, to jest niepoprawny w mojej sprawie.
Tak czy inaczej, Clang wydaje się mieć Buga.
GCC, z drugiej strony, jest co najmniej spójne. To nie dowodzi jednak, że nie ma błędu - może to oznaczać, że ma błąd w obu przypadkach! Chyba, że ktoś wymyśli standard i pokaże ma też bug , zaufam GCC w tym przypadku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-28 14:36:30