2016-09-06 10 views
15

Say mam mój kod skonstruowany w ten sposób:Czy w tym przypadku można napisać specjalizację szablonów w pliku cpp?

  • header1.h

    template <class T, template<class> class C> 
    struct metafunction { 
        using type = typename C<T>::type; 
    }; 
    
    inline namespace msn { 
        template <class T> struct implementation; 
    } 
    
    // uses the *implementation* not defined in the header! 
    template <class T> 
    struct use_case { 
        using type = typename metafunction<T, implementation>::type; 
    }; 
    
  • cpp1.cpp

    #include <header1.h> 
    
    // I'll only need this in this compilation unit, so the 
    // question is: "Is this a good place to define it?" 
    template <> 
    struct implementation<int> { 
        using type = int; 
    }; 
    
    int main() { 
        using tt = int; 
        // is this point of instantiation OK due to 
        // the existence of a specialization in the same cpp file? 
        using tt = use_case<int>::type; 
    
        tt var; 
        (void)var; 
    } 
    

Moja Warunkiem jest to, że będę tylko użyj określonej specjalizacji w plikach cpp, więc nie będę musiał zajmować się problemami z linkerem. Wiem, że to nie zadziała dla pliku cpp2.cpp, w tym header1.h i próbuje po prostu użyć use_case<int> lub przedefiniować implementation<int>, który narusza ODR. Pytam więc, czy ten kod jest analogiczny do jego kodu linear form (wersja, w której wszystko jest umieszczane w jednym pliku cpp z zgodną kolejnością), który (podobno) kompiluje się dobrze.

+0

W tym celu można użyć szablonów "zewnętrznych". –

+0

@KerrekSB Uległe mnie wbudowanym przestrzeniom nazw.Przypuśćmy, że nie mam C++ 11, że kod (jak podano) jest źle sformułowany? –

+0

Jakiego dodatkowego szczegółu szukasz? – Barry

Odpowiedz

8

Tak, o ile jest używany tylko w tej samej jednostce tłumaczeniowej, jest dobrze uformowany.

Należy pamiętać, że efekt #include jest taki, że jeśli plik z odniesieniem jest wstawiany dosłownie do jednostki tłumaczeniowej.

To właśnie jest #include.

Z tego można wyciągnąć kilka wniosków:

Every C++ jednostka tłumaczenie jest pojedynczy wirtualny plik.

Dlatego każda specjalizacja w dobrze uformowanej jednostce tłumaczeniowej odnosi się do tej samej jednostki tłumaczeniowej, która ją definiuje.

Q.E.D.

0

Ogólnie, zgadzam się z odpowiedzią @ Sam, ale zrobiłbym taką specjalizację tylko dla lokalnych typów. Przez "typ lokalny" rozumiem typ, który jest dostępny tylko w tej jednostce tłumaczeniowej, np. klasa zdefiniowana tylko w tym pliku .cpp (w anonimowym obszarze nazw).

Powodem jest to, że kiedy specjalizuje się w ten sposób na typie, który jest szeroko dostępny, szerszy niż specjalizacja, bardzo łatwo jest mieć naruszenie ODR (One Definition Rule). Jeśli w przyszłości inny kod zacznie używać szablonu tego samego typu, łatwo zrozumieć, że otrzymujesz dwa wystąpienia szablonu, które nie są takie same (jeden ze specjalizacją, a drugi bez niego). W takim przypadku jest to naruszenie ODR i zachowanie nie jest zdefiniowane.

Tak więc nie jest to dobry kandydat do "lokalnej" specjalizacji.

Jeśli nadal chcesz mieć specjalizację lokalnie w pliku .cpp, może chcesz dodać dodatkowy tag do parametrów szablonu (który wymaga również dodania innego parametru do oryginalnego szablonu), a ten znacznik będzie z typ lokalny (np. określający struct private_tag{}; wewnątrz anonimowego obszaru nazw w tym pliku i wykorzystujący go w specjalizacji). W ten sposób specjalizacja ma unikalny typ, którego nie można używać w żadnej innej jednostce organizacyjnej, dzięki czemu jesteś bezpieczny przed naruszeniem ODR.

Powiązane problemy