Ignoring repeated explicit instances of template classes in C ++

If I have a class:

template <typename T> class MyClass { // ... }; 

and I explicitly create it:

 template class MyClass<int>; template class MyClass<int>; // second time 

I get an error for some compilers (e.g. Clang, but not in VC ++ 2010). Why do I want to do this? Well, in some cases, T may be a typedef for another type.

 template class MyClass<my_type_1>; template class MyClass<my_type_2>; 

With certain build options, my_type_1 same as my_type_2 , and in other cases it is different. How can I make sure the above compilation in all scenarios? Is there a way to ignore instance duplication?

+4
source share
3 answers

Do not specialize in typedefs, but specialize in the corresponding base types (e.g. int). That way, you can enter typedef as many times / several times as you want, and you still always get the specializations you want.

+3
source

You may find another way to explicitly create an instance of template so that you can perform metaprogramming on it.

Then, instead of doing one instance per line, do it all in a package. Run the n ^ 2 algorithm on them (at compile time) to eliminate duplicates (or, frankly, you can probably skip this: depending on how you create the template, this may not matter).

Something like this, assuming Instantiate< Template, types< blah, foo, bar > > actually creates an instance of the list in the template passed as the first argument:

 #include <utility> #include <type_traits> template<typename T> struct Test {}; template<typename... Ts> struct types {}; template<template<typename>class Template, typename Types> struct Instantiate {}; template<template<typename>class Template, typename T0, typename... Ts> struct Instantiate<Template, types<T0, Ts...>>: Instantiate<Template, types<Ts...>> { Template<T0>& unused(); }; template<typename U, typename Types> struct prepend; template<typename U, template<typename...>class pack, typename... Ts> struct prepend< U, pack<Ts...> > { typedef pack<U, Ts...> types; }; template<typename U, typename Types> using Prepend = typename prepend<U, Types>::types; template<typename U, typename Types, typename=void> struct remove_type_from_types; template<typename U, template<typename...>class pack> struct remove_type_from_types<U, pack<>, void> { typedef pack<> types; }; template<typename U, template<typename...>class pack, typename T0, typename... Ts> struct remove_type_from_types< U, pack<T0, Ts...>, typename std::enable_if< std::is_same<U, T0>::value >::type >: remove_type_from_types< U, pack<Ts...> > {}; template<typename U, template<typename...>class pack, typename T0, typename... Ts> struct remove_type_from_types< U, pack<T0, Ts...>, typename std::enable_if< !std::is_same<U, T0>::value >::type > { typedef Prepend< T0, typename remove_type_from_types< U, pack<Ts...> >::types > types; }; template<typename Types> struct remove_duplicates { typedef Types types; }; template<template<typename...>class pack, typename T0, typename... Ts> struct remove_duplicates<pack<T0, Ts...>> { private: typedef typename remove_type_from_types< T0, pack<Ts...> >::types filtered_tail; typedef typename remove_duplicates< filtered_tail >::types unique_tail; public: typedef Prepend< T0, unique_tail > types; }; template<typename Types> using RemoveDuplicates = typename remove_duplicates<Types>::types; static Instantiate<Test, RemoveDuplicates<types<int, double>> > unused; int main() { } 

As already noted, you can probably get rid of the entire delete-duplicates bit due to the way I create the template instance. I'm also not sure that for each instance of the template it’s enough to use it (i.e. that it will not be optimized in some way, and that this symbol will be exported).

(The recursion depth is n in the number of types, and the general work is done n^2 in the number of types: it is shallow and fast enough for any reasonable number of types, I suspect. The unique Fancier type is difficult to remove due to the lack of a weak order on bare types .. .)

+3
source

You can define a preprocessor flag for your configuration, and then place the template inside the #ifdef block.

+2
source

Source: https://habr.com/ru/post/1486880/


All Articles