2009-07-22 12 views
8

Mam następujący kod (Przepraszam za dużego fragmentu kodu, ale nie mogłem sprowadzić więcej)niejednoznaczne szablon niesamowitość

template <bool B> 
struct enable_if_c { 
     typedef void type; 
}; 

template <> 
struct enable_if_c<false> {}; 

template <class Cond> 
struct enable_if : public enable_if_c<Cond::value> {}; 

template <typename X> 
struct Base { enum { value = 1 }; }; 

template <typename X, typename Y=Base<X>, typename Z=void> 
struct Foo; 

template <typename X> 
struct Foo<X, Base<X>, void> { enum { value = 0 }; }; 

template <typename X, typename Y> 
struct Foo<X, Y, typename enable_if<Y>::type > { enum { value = 1 }; }; 

int main(int, char**) { 
     Foo<int> foo; 
} 

Ale to nie skompilować z gcc (v4.3) z

foo.cc: In function ‘int main(int, char**)’: 
foo.cc:33: error: ambiguous class template instantiation for ‘struct Foo<int, Base<int>, void>’ 
foo.cc:24: error: candidates are: struct Foo<X, Base<X>, void> 
foo.cc:27: error:     struct Foo<X, Y, typename enable_if<Y>::type> 
foo.cc:33: error: aggregate ‘Foo<int, Base<int>, void> foo’ has incomplete type and cannot be defined 

OK, więc jest niejednoznaczna. ale nie spodziewałem się, że to będzie problem, ponieważ przy użyciu specjalizacji prawie zawsze będzie jakaś niejednoznaczność. Jednak ten błąd jest wywoływany tylko podczas używania klasy z enable_if<...>, jeśli zastąpię ją klasą podobną do poniższej, nie ma problemu.

template <typename X, typename Y> 
struct Foo<X, Y, void > { enum { value = 2 }; }; 

Dlaczego ta klasa nie wywołuje dwuznaczności, podczas gdy inni nie? Czy te dwie rzeczy nie są takie same dla klas o wartości true :: value? W każdym razie wszelkie wskazówki dotyczące tego, co robię źle, są doceniane.

Dzięki za odpowiedzi, moim prawdziwym problemem (aby kompilator wybrać swój pierwszy specjalizacji) został rozwiązany przez zastąpienie struct Foo<X, Base<X>, void> z struct Foo<X, Base<X>, typename enable_if< Base<X> >::type > który wydaje się działać tak, jak chcę.

+0

Edytor przecinków nie jest wysiwyg w stosunku do

+0

Naprawiłem go wcześniej, nadpisałeś moje zmiany :) Jeśli chcesz, możesz wrócić do mojej edycji (użyłem przycisku "10101", który automatycznie oznacza rzeczy jako kod, powinieneś użyć ten przycisk też). –

+0

Uhjm ... Zrobiłem to ponownie bez czytania twojego komentarza litb –

Odpowiedz

12

Istotą pytaniem jest to, że masz:

template <typename X, typename Y, typename Z> 
struct Foo {}; 

template <typename X> 
struct Foo<X, Base<X>, void> {};     // #1 

template <typename X, typename Y> 
struct Foo<X, Y, typename whatever<Y>::type> {}; // #2 

i starasz się dopasuj do

Foo<int, Base<int>, void> 

Oczywiście obie specjalizacje są zgodne (pierwsza z X = int, drugi z X = int, Y = Base<int>).

Zgodnie ze standardem, rozdział 14.5.4, jeżeli istnieje więcej pasujących specjalizacji, konstruuje się między nimi uporządkowanie częściowe (jak zdefiniowano w 14.5.5.2) i używa się najbardziej wyspecjalizowanego. W twoim przypadku żaden z nich nie jest bardziej wyspecjalizowany niż drugi. (Po prostu, szablon jest bardziej wyspecjalizowany niż inny, jeśli możesz zastąpić każdy parametr typu tego ostatniego szablonem jakimś typem iw rezultacie uzyskać podpis pierwszego z nich, a jeśli masz whatever<Y>::type i zastąpisz Y z Base<X>, otrzymasz whatever<Base<X> >::type nie void, czyli nie ma przetwarzanie wykonywane.)

Jeśli zastąpić #2 z

template <typename X, typename Y> 
struct Foo<X, Y, void > {};      // #3 

kandydat ustawić ponownie zawiera zarówno szablonów, jednak nr 1 jest bardziej wyspecjalizowany następnie # 3 i jako takie jest zaznaczona.

+0

to odpowiada na moje pytanie, ale mój podstawowy problem pozostaje. Nie wiem, jak należy tu zadawać kolejne pytania, ale spróbuję komentarza. Czy jest jakiś sposób, aby uzyskać to, co chcę, aby uzyskać # 1 wybrane po zaindeksowaniu "Foo "? jak oszukiwanie kompilatora, aby sądzić, że # 1 jest być może bardziej wyspecjalizowanym. – keis

+0

+1, gdzie +10 byłoby bardziej odpowiednie. Zajęło mi tak dużo czasu napisanie odpowiedzi, że pokonałeś mnie przez * tylko * 29 minut :) –

+2

@keis: Problem polega na tym, że specjalizacja jest częściowym porządkiem, aw niektórych przypadkach dwa elementy nie są naprawdę uporządkowane. Teraz, jeśli podajesz, co naprawdę chcesz osiągnąć (napisz szablon taki, że gdy instancja z int będzie miała wartość 1, a gdy instancja z X będzie miała wartość 2), możesz uzyskać lepsze wskazówki –

-1

nie brakuje

< 

symbol?

+0

< and > został utracony w parserze HTML strony, mam nadzieję, że naprawiłem go teraz. – keis

-2

myślę, że brakuje '<', szablon powinien wyglądać następująco:

template< typename T > 
struct myStruct 
{}; 

//OR 

template< class T > 
struct myStruct 
{}; 
+0

Och, naprawiłeś kod, ta odpowiedź jest teraz zbędna. – DeusAduro

+0

Po co mnie powaliłeś ... Odpowiedziałem przed edytowaniem kodu, w którym to momencie moja odpowiedź miała sens ... – DeusAduro

+1

Ponieważ to nie ma sensu * teraz *. Jeśli nie chcesz edytować, aby odpowiedzieć na nowe pytanie, całkowicie usuń odpowiedź. – avakar