Can I declare a template specialization?

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

So, let's say I have a list of types:

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

This contains some objects:

 struct foo{}; struct bar{}; struct quux{}; using objects = typelist<foo, bar, quux>; 

Now I have a template class ( baz ) that can accept any of these objects. But, due to the size of the code and compilation time, I want to have an implementation of my template method in the 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 that I have many classes, such as baz , and the list of objects they work with is also constantly changing. So ... anyway, can I save my only list of objects and use it in the cpp file of each baz object for specialization? Then all I need to do is update my list when I have a new object and all the object files are restored.

+7
c ++ templates metaprogramming template-specialization
source share
5 answers

String template <> class baz<foo>; forward - declares specialization, not an instance of the template, which I suppose is what you want.

I don’t think there is a direct way to do this, you will need to do metaprogramming. You can use Boost.Preprocessor to generate all the necessary 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 a preprocessor, but this will require additional requirements for the baz type. The point is to use a type in the context where it should be created, including all its methods.

+9
source share

I am sure that this is not possible without using a preprocessor. You may be able to restore the package of template arguments from the argument, but you should actually pass an instance of the argument that seems suboptimal. Secondly, explicit template instances are not allowed in the block area (i.e., in the template function), so there is no way to write a template that explicitly creates an instance of another template.

As Nir points out, why don't you just use the X Macro ?

 #define MY_FOREACH_TYPES(func, ...) \ func(type1, ##_VA_ARGS__) \ func(type2, ##_VA_ARGS__) \ #define MY_INSTANTIATE(Type, Class) \ template <> class Class<Type>; MY_FOREACH_TYPES(MY_INSTANTIATE, bar) 

Now just update MY_FOREACH_TYPES when your type list changes.

+3
source share

First of all: The correct syntax for explicitly instantiating a class

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

not template <> class baz<foo> , which is an explicit specification of the class template (forward-declaration).

One possibility might be to instantiate a class that looks like this:

 template <template <typename> class T, typename... Args> class for_each_class : T<Args>... { }; // Instantiate template class for_each_class<baz, foo, bar, quux>; 

which will force the implicit instantiation of baz<foo> , baz<bar> , baz<quux> . Well, but you want to create this from a typelist . typelist is already a specialized template, and in C ++ there is no way to typelist over template parameters in typelist from the "outside world of typelist ".

Another possibility might be to use a macro, but even in a macro you cannot use your original typelist . I would end up that your problem is not resolved considering the typelist .

As a solution, I could leave the template instance in the compiler, if possible. In this case, unused templates are not created. Slow compilation is related to how metaprograms are specified.

+3
source share

Version for working with a conventional preprocessor

 //Header file #define BAZ_OBJS \ BAZ_BEGIN foo \ BAZ_AND bar \ BAZ_AND quux \ BAZ_END #define BAZ_BEGIN #define BAZ_AND , #define BAZ_END using objects = typelist<BAZ_OBJS>; #undef BAZ_BEGIN #undef BAZ_AND #undef BAZ_END #define BAZ_BEGIN BAZ_EXTERN template class baz< #define BAZ_END >; #define BAZ_AND BAZ_END BAZ_BEGIN #ifdef MY_IMPLEMENTATION_CPP //cpp should define it before including the header file #define BAZ_EXTERN #else #define BAZ_EXTERN extern #endif BAZ_OBJS 
+2
source share

That would do the trick. In the end, with the senialization of a list of types with one (or none) type.

 template <typename Head, typename ...Tail> struct typelist{ typedef baz<Head> head_t; typedef typelist<Tail...> tail_t; }; 
+1
source share

All Articles