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 .. .)