Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it ok to write template specializations in a cpp file in this case?

Say I have my code structured this way:

  • 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; 
    }
    

My precondition is that I'll only use the specific specialization(s) inside the cpp file(s) so I won't have to deal with linker problems. I know this won't work for a cpp2.cpp file including header1.h and trying to just use use_case<int> or redefining an implementation<int> that violates the ODR. So what I'm asking is whether this code is analogous to its linear form (a version where everything is put into a single cpp file with a conforming order) that (apparently) compiles fine.

like image 449
Lorah Attkins Avatar asked Sep 06 '16 23:09

Lorah Attkins


People also ask

Can template be defined in CPP?

A template is not an actual class or function, but a "pattern" that the compiler uses to generate a family of classes or functions. In order for the compiler to generate the code, it must see both the template definition (not just declaration) and the specific types/whatever used to "fill in" the template.

What is the use of template specialization?

This is called template specialization. Template allows us to define generic classes and generic functions and thus provide support for generic programming. Generic programming is an approach where generic data types are used as parameters in algorithms so that they work for variety of suitable data types.

Why do we write templates in header files?

To have all the information available, current compilers tend to require that a template must be fully defined whenever it is used. That includes all of its member functions and all template functions called from those. Consequently, template writers tend to place template definition in header files.

Are template specializations inline?

An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.


2 Answers

Yes, as long as this is used only within the same translation unit, this is well-formed.

Keep in mind that the effect of #include is as-if the referenced file is inserted verbatim into the translation unit.

That's what an #include is.

From this, we can draw several conclusions:

Every C++ translation unit is a single virtual file.

Therefore, every specialization in a well-formed translation unit is referenced in the same translation unit that defines it.

Q.E.D.

like image 179
Sam Varshavchik Avatar answered Sep 22 '22 03:09

Sam Varshavchik


Generally, I agree with @Sam's answer, but I would do such a specialization only for local types. With "local type" I mean a type that is accessible only in this translation unit, e.g. a class that is defined only in this .cpp file (in an anonymous namespace).

The reason is that when specialization in this way on a type that is widely accessible, wider than the specialization, it's very easy to have an ODR (One Definition Rule) violation. If somewhen in the future another code starts using the template with the same type, it's easy to understand that you get two instantiations of the template which aren't the same (one with the specialization and one without it). In such a case, this is an ODR violation and the behavior isn't defined.

So int it definitely not a good candidate for a "local" specialization.

If you still want to have the specialization locally in the .cpp file, maybe you want to add an additional tag to the template parameters (which requires adding another parameter to the original template too), and this tag will be with a local type (e.g. defining struct private_tag{}; inside an anonymous namespace in this file and using it in the specialization). This way, the specialization has a unique type that can't be used in any other TU, so you are safe from ODR violation.

like image 34
Yehezkel B. Avatar answered Sep 19 '22 03:09

Yehezkel B.