Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Alias for list of template parameters

I have a lot of C++ classes that use the same list of template parameters

template<typename T, typename Index, typename Bool, typename Data, Index n_x, Index n_u, Index n_c, Index n_w>
class A {
   ...
};

template<typename T, typename Index, typename Bool, typename Data, Index n_x, Index n_u, Index n_c, Index n_w>
class B {
   ...
};

template<typename T, typename Index, typename Bool, typename Data, Index n_x, Index n_u, Index n_c, Index n_w>
class C {
   ...
};

You get the idea. Then I instantiate them like

A<T, Index, Bool, Data, n_x, n_u, n_c, n_w> a;
B<T, Index, Bool, Data, n_x, n_u, n_c, n_w> b;
C<T, Index, Bool, Data, n_x, n_u, n_c, n_w> c;

Is there a way to somehow create an alias for this bundle of template parameters so that I don't have to keep re-typing the argument list?

I have something like this in mind...

using Params = T, Index, Bool, Data, n_x, n_u, n_c, n_w;
A<Params> a;
B<Params> b;
C<Params> c;

I realize that I could create a separate class which just defines types, and use that. But I am wondering if there is a way of doing this without defining a new class.

EDIT

I do not want to use macros.

I also do not want to use defaults because that would require ensuring that the defaults are uniform across a bunch of files. I realize that I could define a new header of defaults and just include that in all of the files, but that just seems like bad programming.

like image 581
bremen_matt Avatar asked Sep 09 '25 10:09

bremen_matt


2 Answers

Not exactly what you asked but not so different...

But require a little work.

You can solve with a struct, foo, with a double layer of template management.

template <typename T, typename Index, typename Bool, typename Data,
          Index I1, Index I2, Index I3, Index I4>
struct foo
 { 
   template <template <typename, typename X, typename, typename, X, X, X, X>
                       class Cont>
   using type = Cont<T, Index, Bool, Data, I1, I2, I3, I4>;
 };

A first layer, the struct layer, with the types/values you want to fix (T, Index, Bool, Data, n_x, n_u, n_c, n_w, in your example).

A second layer, the using layer, with the variable template element (A, B and C, in your example.

You can also add a using alias foot_t to simplify the use

template <template <typename, typename X, typename, typename, X, X, X, X>
                    class Cont, typename C>
using foo_t = typename C::template type<Cont>;

Now you can fix types and values (the first layer) with a using

using f = foo<T, Index, Bool, Data, n_x, n_u, n_c, n_w>;

and declare variable activating second layer using foo_t

foo_t<A, f> a;
foo_t<B, f> b;
foo_t<C, f> c;

The following is a full working example

#include <vector>
#include <iostream>

template <typename T, typename Index, typename Bool, typename Data,
          Index n_x, Index n_u, Index n_c, Index n_w>
class A { };

template <typename T, typename Index, typename Bool, typename Data,
          Index n_x, Index n_u, Index n_c, Index n_w>
class B { };

template <typename T, typename Index, typename Bool, typename Data,
          Index n_x, Index n_u, Index n_c, Index n_w>
class C { };

template <typename T, typename Index, typename Bool, typename Data,
          Index I1, Index I2, Index I3, Index I4>
struct foo
 { 
   template <template <typename, typename X, typename, typename, X, X, X, X>
                       class Cont>
   using type = Cont<T, Index, Bool, Data, I1, I2, I3, I4>;
 };

template <template <typename, typename X, typename, typename, X, X, X, X>
                    class Cont, typename C>
using foo_t = typename C::template type<Cont>;


int main ()
 {
   using T     = float;
   using Index = std::size_t;
   using Bool  = bool;
   using Data  = std::vector<std::string>;

   constexpr std::size_t n_x { 0U };
   constexpr std::size_t n_u { 1U };
   constexpr std::size_t n_c { 2U };
   constexpr std::size_t n_w { 3U };

   using f = foo<T, Index, Bool, Data, n_x, n_u, n_c, n_w>;

   foo_t<A, f> a;
   foo_t<B, f> b;
   foo_t<C, f> c;

   static_assert( std::is_same<decltype(a),
                     A<T, Index, Bool, Data, n_x, n_u, n_c, n_w>>{}, "!" );
   static_assert( std::is_same<decltype(b),
                     B<T, Index, Bool, Data, n_x, n_u, n_c, n_w>>{}, "!" );
   static_assert( std::is_same<decltype(c),
                     C<T, Index, Bool, Data, n_x, n_u, n_c, n_w>>{}, "!" );
 }
like image 176
max66 Avatar answered Sep 11 '25 08:09

max66


You could replace the alias by a define, not perfect, but easy solution and it works.

#define PARAMS T, Index, Bool, Data, n_x, n_u, n_c, n_w
A<PARAMS> a;
B<PARAMS> b;
C<PARAMS> c;

Note: no ; at the end of the define.

like image 22
Vuwox Avatar answered Sep 11 '25 08:09

Vuwox