Search code examples
c++templatesmetaprogrammingtemplate-specialization

Can I declare a template instantiation from a typelist?


Pretty sure I know the answer to this already, but it's worth a shot.

So, say I have a typelist:

template <typename ...Ts>
struct typelist{};

That contains some objects:

struct foo{};
struct bar{};
struct quux{};

using objects = typelist<foo, bar, quux>;

Now I have a templated class (baz) that can take any of these objects. But, due to codebase size and compilation times, I want to have the implementation of my templated method in a cpp file.

So at the bottom of baz.cpp I have:

template <> class baz<foo>;
template <> class baz<bar>;
template <> class baz<quux>;

The problem is I have lots of classes like baz, and the list of objects that they work with is also ever changing. So... is there anyway I can keep my single typelist of objects and use that in the cpp file of each baz-like object to specialize? Then, all I have to do is update my typelist when I have a new object and all the object files will rebuild.


Solution

  • The template <> class baz<foo>; line forward-declares a specialization and not a template instantiation, which, I assume, is what you want.

    I don't think there's a direct way to do this, you'll have to do some metaprogramming. You can use Boost.Preprocessor to generate all the needed code:

    #define TYPES (foo)(bar)(quux)
    
    using objects = typelist< BOOST_PP_SEQ_ENUM(TYPES) >;
    
    // Generate extern template declarations in the header
    #define EXTERN_TEMPLATE_BAZ(r, data, arg)\
        extern template class baz< arg >;
    
    BOOST_PP_SEQ_FOR_EACH(EXTERN_TEMPLATE_BAZ, _, TYPES)
    
    // Generate template instantiations in the .cpp
    #define TEMPLATE_BAZ(r, data, arg)\
        template class baz< arg >;
    
    BOOST_PP_SEQ_FOR_EACH(TEMPLATE_BAZ, _, TYPES)
    

    There may be a way to do this without preprocessor but doing this would impose additional requirements on the baz type. The point is to use the type in a context where it has to be instantiated, including all its methods.