Przeładowanie funkcji szablonu identycznymi podpisami, dlaczego to działa?
Minimalny program:
#include <stdio.h>
#include <type_traits>
template<typename S, typename T>
int foo(typename T::type s) {
return 1;
}
template<typename S, typename T>
int foo(S s) {
return 2;
}
int main(int argc, char* argv[]) {
int x = 3;
printf("%d\n", foo<int, std::enable_if<true, int>>(x));
return 0;
}
wydajność:
1
Dlaczego nie daje to błędu kompilacji? Gdy wygenerowany zostanie kod szablonu, nie będzie funkcjiint foo(typename T::type search)
iint foo(S& search)
masz ten sam podpis?
Jeśli nieco zmienisz sygnatury funkcji szablonu, to nadal działa (jak można by się spodziewać po powyższym przykładzie):
template<typename S, typename T>
void foo(typename T::type s) {
printf("a\n");
}
template<typename S, typename T>
void foo(S s) {
printf("b\n");
}
Ale to nie jest, a jedyną różnicą jest to, że jeden ma podpis int, a drugi jest zdefiniowany przez pierwszy parametr szablonu.
template<typename S, typename T>
void foo(typename T::type s) {
printf("a\n");
}
template<typename S, typename T>
void foo(int s) {
printf("b\n");
}
Błąd kompilatora (Clang):
test.cpp:26:2: error: call to 'foo' is ambiguous
foo<std::enable_if<true, int>>(3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(typename T::type s) {
^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(int s) {
^
1 error generated.
Używam kodu podobnego do tego dla projektu, nad którym pracuję, i obawiam się, że istnieje subtelnie język, którego nie rozumiem, który spowoduje pewne niezdefiniowane zachowanie w niektórych przypadkach. Powinienem również wspomnieć, że kompiluje się zarówno w Clang, jak iw VS11, więc nie sądzę, aby był to tylko błąd kompilatora.
Edytuj: poprawiono drugi przypadek (literówka); dodano komunikat o błędzie od Clang.
Edytuj # 2: Dla tych, którzy pytali, co oznacza typ T ::.
Zhttp://en.cppreference.com/w/cpp/types/enable_if:
szablon <bool B, klasa T = void> struct enable_if;
Jeśli B jest prawdziwe, std :: enable_if ma typ typef publicznego członka, równy T; w przeciwnym razie nie ma typedef członka.
enable_if jest strukturą. Zasadniczo, jeśli wyrażenie obliczone w pierwszym parametrze szablonu enable_if jest prawdziwe (aw przypadku moich przykładów powyżej, to jest), wtedy będzie członek publicznytype
który ma ten sam typ co drugi parametr szablonu.
W przypadkuenable_if<true, int>
, enable_if :: type ma typ int.