2014-12-15 15 views
11

Mam następujący C++ kod:Dlaczego poniższy kod powoduje wystąpienie szablonu?

//Define to 1 to make it work 
#define WORKS 0 

#if WORKS 
    template< typename T > struct Foo; 
#else 
    template< typename T > 
    struct Foo { 
     T t; 
    }; 
#endif 

class Bar; //Incomplete type 

void fFooBar(Foo<Bar> const & foobar) { } 

void f(Foo<Bar> const & foobar) { 
    fFooBar(foobar); 
} 

int main() { 
    return 0; 
} 

Jeśli działa jest definiowana jako 0 (szablon struktura jest zdefiniowana) kod nie skompilować, ponieważ próbuje instancję w fFooBar(foobar); i nie powiedzie się, ponieważ Bar jest niekompletny.

Jeśli WORK jest zdefiniowany jako 1 (szablon struktury jest niezdefiniowany), kod się kompiluje.

Zgodnie ze standardem szablon nie powinien być inicjowany, chyba że wymagany jest kompletny typ (co nie ma miejsca w przypadku const&) lub zmieniłby semantykę kodu (co również nie ma miejsca, i againt, to samo powinno się stać, jeśli szablon nie został zdefiniowany).

Co dziwne, program można skompilować, usuwając informacje z kompilatora. Ale fakt, że MSVC, gcc i clang wszystkie robią to samo powoduje, że myślę, że musi istnieć ku temu powód.

+4

ADL, myślę. Podobny problem, jak http://stackoverflow.com/questions/25925551/gcc-and-clang-implicitly-instantiate-template-arguments-during-operator-overload –

+1

@ T.C. [temp.inst]/7? – Columbo

+0

@Columbo Rzeczywiście. –

Odpowiedz

5

Po utworzeniu program można skompilować w Clang, kwalifikując połączenie pod numerem fFooBar z ::. Standard wymaga, aby wyszukiwanie nazwy zachowywało się inaczej, gdy w wywołaniu funkcji używana jest niekwalifikowana nazwa.

[basic.lookup.argdep]/1

Gdy przyrostek ekspresja w wywołaniu funkcji (5.2.2) jest nieograniczone ID inne nazw nie uważa podczas zwykłej uwarunkowanej odnośnika (3.4.1) mogą być wyszukiwane, aw tych przestrzeniach nazw można znaleźć deklaracje funkcji znajomych (11.3), które nie są widoczne.

Badając (nieco skomplikowane) przepisy dotyczące procesu zależnej Lookup Argument sugeruje, że może być realizowany tylko prawidłowo w sposób, który wymagałby od konkretyzacji specjalizacji szablonu w rodzaju argumentów do rozmowy.

[basic.lookup.argdep]/2

Dla każdego typu parametru T w wywołaniu funkcji jest zbiorem zero lub więcej powiązanych nazw i zestaw zero lub więcej powiązanych klas uznać. Zestawy nazw i klas jest określona całości typów argumentów funkcji [...]

  • Jeśli T jest typem klasy (w tym zawodowych), związane z nim zajęcia są: klasa sama w sobie; klasa, której jest członkiem, jeżeli istnieje; oraz jego bezpośrednie i pośrednie klasy bazowe.

Jedna z interpretacji jest to, że klasa jest wymagana będzie pełna, jeśli jest on stosowany w rodzaju argument niewykwalifikowanego wywołania funkcji. Alternatywną interpretacją jest to, że ADL powinien powodować tylko tworzenie szablonów, które są kompletne.

albo zachowanie jest zgodne z normą według projektu roboczej N3337

[temp.inst]/6

Jeżeli proces rozdzielczości przeciążenie określenia prawidłowej funkcji połączenia bez uruchamianiu klasę Definicja szablonu nie jest określona, ​​czy dana instancja faktycznie ma miejsce.

template <class T> struct S { 
    operator int(); 
}; 

void f(int); 
void f(S<int>&); 
void f(S<float>); 
void g(S<int>& sr) { 
    f(sr); // instantiation of S<int> allowed but not required 
      // instantiation of S<float> allowed but not required 
}; 

[temp.inst]/7

Jeśli wymagana jest niejawna instancji o specjalizacji szablonu klasy i szablon jest zadeklarowana ale nie określona, ​​program jest źle sformułowane.

+0

Tak, właśnie to znalazłem. Odpowiadałem sobie, ale cieszę się, że odpowiedziałeś, ponieważ nie lubię tego typu auto-erotyzmu opartego na Internecie. –

+0

Chociaż nie jestem pewien, instrukcja/7 powoduje WORKS = 1 do kompilacji. Mówi, że jeśli specjalizacja jest wymagana, program jest źle sformułowany. Nie mówi tak naprawdę, co się dzieje, gdy specjalizacja nie jest wymagana (co jest moim przypadkiem). –

+0

'można go poprawnie zaimplementować tylko w sposób, który wymagałby utworzenia szablonu". Ok, mogę z tym żyć. Ale dlaczego to działa, gdy definicja jest pomijana? –

Powiązane problemy