Poniższy kod działa poprawnie na VS2015:Template Selection Function podstawie typu zagnieżdżonego
struct Foo
{
using Bar = int;
auto operator()() { return "Foo!"; }
};
template <typename Callable, typename CodeType> // <<< CodeType is a template param
void funky(CodeType code, Callable func)
{
cout << "Generic: " << code << ", " << func() << endl;
}
template <typename HasBar>
void funky(typename HasBar::Bar code, HasBar func) // <<< The code type is a nested type
{
cout << "Has Bar: " << code << ", " << func() << endl;
}
int main()
{
Foo foo;
funky(3, []() { return "Lambda!"; });
funky(3, foo);
return 0;
}
Druk:
Generic: 3, Lambda!
Has Bar: 3, Foo!
Jednak it does not compile na gcc/brzękiem, narzekając:
In function 'int main()':
27:16: error: call of overloaded 'funky(int, Foo&)' is ambiguous
27:16: note: candidates are:
12:6: note: void funky(CodeType, Callable) [with Callable = Foo; CodeType = int]
18:6: note: void funky(typename HasBar::Bar, HasBar) [with HasBar = Foo; typename HasBar::Bar = int]
Niejednoznaczność jest rozwiązana poprawnie przez VS2015 (co nie oznacza, że jest to zgodne z d o).
Jak mogę to skompilować i poprawnie uruchomić na Clang/gcc?
Pomyślałem o użyciu std::enable_if
, ale nie mogłem zrobić tego, co chcę (najprawdopodobniej użyłem go niepoprawnie). Jeśli jest to droga, w jaki sposób należy ją zastosować, aby rozwiązać tę niejednoznaczność?
UPDATE:
Dodawanie typename HasBar :: Bar do params szablonu dostaje gcc/Clang zbudować i uruchomić kod poprawnie:
template <typename HasBar, typename HasBar::Bar>
void funky(typename HasBar::Bar code, HasBar func) // <<< The code type is a nested type
{
cout << "Has Bar: " << code << ", " << func() << endl;
}
Wydaje się poinformować kompilator, że istnieje druga , wartość parametru szablonu non-type (nieużywana w kodzie funkcji), która jest typu typename HasBar::Bar
. If typename HasBar::Bar
nie istnieje, SFINAE usunie tę funkcję ze zbioru przeciążeniowego i zostanie wybrana forma ogólna.
Jednak, kiedy już istnieje, nie wiem, dlaczego ta funkcja będzie miała pierwszeństwo przed pierwszą. Chyba dlatego, że jest bardziej wyspecjalizowany - choć specjalizacja nie jest używana w samym kodzie. Jednak w tym przypadku było już ono bardziej wyspecjalizowane nawet przed nowym paramem!
Jednak, w tym przypadku VS2015 zawsze wybiera formę ogólną daje złą odpowiedź!
Czy istnieje pewna składnia (i/lub sposób obejścia), który będzie działał we wszystkich przypadkach?
W jaki sposób użyłeś 'enable_if'? Czy użyłeś go, aby włączyć drugie przeciążenie, lub * wyłączyć * pierwsze przeciążenie? –
Właściwie próbowałem różnych rzeczy, ale nie jestem pewien, czy były poprawne. Jak * powinno * być użyte tutaj? –
Spodziewałbym się, że druga funkcja będzie bardziej wyspecjalizowana, a tym samym będzie preferowanym przeciążeniem, jeśli ma to zastosowanie (więc VS miałoby rację). Czy ktoś może to komentować? – MikeMB