2013-02-25 15 views
11

Mam klasę szablonu, którą deklaruję w nagłówku z jedną metodą i bez definicji tej metody w nagłówku. W pliku .cc definiuję specjalizacje tej metody , nigdy nie deklarując ich w nagłówku. W innym pliku .cc wywołuję metodę dla różnych parametrów szablonu, dla których istnieją specjalizacje. Wygląda to tak:Specjalizacja członka klasy szablonu bez deklaracji w nagłówku

Foo.h:

template<typename T> 
class Foo { 
public: 
    static int bar(); 
}; 

foo.cc:

#include "foo.h" 

template<> 
int Foo<int>::bar() { 
    return 1; 
} 

template<> 
int Foo<double>::bar() { 
    return 2; 
} 

main.cc:

#include <iostream> 
#include "foo.h" 

int main(int argc, char **argv) { 
    std::cout << Foo<int>::bar() << std::endl; 
    std::cout << Foo<double>::bar() << std::endl; 
    return 0; 
} 

Ten program kompiluje i łączy z powodzeniem z gcc 4.7.2 dla wszystkich standardów C++ (C++ 98, gnu ++ 98, C++ 11 i gnu ++ 11). Dane wyjściowe to:

1 
2 

To ma dla mnie sens. Ponieważ jednostka tłumaczeniowa main.cc nie widzi definicji bar() ani żadnych jej specjalizacji, oczekuje ona, że ​​wywołania do bar() będą wykorzystywać jawne tworzenie nieokreślonej definicji bar() w jakiejś innej jednostce tłumaczeniowej. Ale ponieważ nazwa "mangling" jest przewidywalna, specjalizacje w foo.cc mają te same nazwy symboli co jawne instancje o nieokreślonej definicji, więc main.cc może korzystać z tych specjalizacji bez zadeklarowania ich w tej jednostce tłumaczeniowej.

Moje pytanie brzmi: czy to jest wypadek, czy też takie zachowanie jest wymagane przez standard C++? Innymi słowy, czy ten kod jest przenośny?

Najważniejszym wcześniejszym pytaniem, które mogłem znaleźć, jest Declaration of template class member specialization, ale nie obejmuje tego konkretnego przypadku.

(W przypadku, gdy zastanawiacie się, dlaczego to ma dla mnie znaczenie, to dlatego, że używam tego kodu jako pewnego rodzaju tabeli przeglądowej w czasie kompilacji i jest znacznie krótszy, jeśli nie deklaruję specjalizacji .)

+2

To raczej dobre pierwsze pytanie! Myślę, że kompilator IBM pozwala zadeklarować swoje specjalizacje za pomocą słowa kluczowego extern, ale nigdy nie zrobił tego sam. –

Odpowiedz

8

standard (C++ 11) wymaga, aby zostać uznane za jawne specjalizacje (ale niekoniecznie zdefiniowane) przed pierwszym użyciem:

(14.7.3/6) Jeśli do szablonu, szablon członkowski lub członek szablonu klasy jest wyraźnie wyspecjalizowany, wtedy specjalizacja ta zostanie zadeklarowana przed pierwszym użyciem tej specjalizacji, która spowodowałaby utworzenie niejawnego wystąpienia, w każdej tra jednostkę, w której takie użycie występuje; diagnostyka nie jest wymagana. Jeśli program nie zapewnia definicji specjalizacji jawnej, a specjalizacja jest używana w sposób, który spowodowałby, że wystąpienie niejawne ma miejsce, lub element jest funkcją wirtualnego elementu, program jest źle sformułowany, nie wymaga diagnostyki . Natychmiastowe tworzenie instancji nigdy nie jest generowane dla jawnej specjalizacji, która jest zadeklarowana, ale nie jest zdefiniowana. [...]

Wierzę, że w praktyce będzie to miało skutek tylko wtedy, gdy definicja głównego szablonu zawiera definicję niewyspecjalizowanej wersji jednej z funkcji członka. Ponieważ w takim przypadku, gdy jawna specjalizacja nie zostanie zadeklarowana, istniejąca podstawowa definicja może zostać wykorzystana do skompilowania funkcji w linii do kodu, a specjalizacja nie zostanie wykorzystana w czasie łącza.

Innymi słowy, jeśli nie ma definicji funkcji składowej zawartej w pierwotnej definicji szablonu, prawdopodobnie można oczekiwać, że sztuczka linkera zadziała w praktyce, ale nie będzie zgodna z tym, co mówi Standard, i że może spowodować poważne problemy, gdy tylko dodasz funkcję wbudowaną do głównego szablonu.

+0

Dzięki. Zdecydowanie zgadzam się, że ten kod jest uszkodzony, jeśli istnieje szablonowa definicja w głównym szablonie. Ale biorąc pod uwagę, że tak nie jest, czy standard mówi cokolwiek o tym, co dzieje się w tym przypadku? Ten akapit wydaje się nie obejmować tego. –

+0

@ TristanSchmelcher Wierzę, że powyższa sekcja obejmuje wszystkie przypadki (chyba że istnieje wyjątek gdzieś nie widziałem). Wyraźnie mówi, że wyraźne specjalizacje muszą zostać zadeklarowane przed użyciem. Więc jeśli plik nagłówka nie deklaruje go, ale main.cpp (który zawiera nagłówek, ale nie .cc) używa go, narusza Standard. – jogojapan

+1

Rozumiem. Myślałem, że termin "implicite tworzenie" nie obejmuje użycia w main.cc, ponieważ nie ma definicji nieokreślonego 'bar()' w zakresie, ale 14.7.1 wydaje się mówić, że liczy się jako niejawna instancja niezależnie. –

Powiązane problemy