Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

template class wrapping a arbitrary type/non-type template class

Tags:

c++

templates

Suppose I have a template class base and a class wrapper which contains a instantiated member of base. I would like to define the class wrapper such that it depends on a template parameter pack, which is simply "passed" to the instantiated member of base.

For example consider the following code, which works fine.

#include <iostream>

template <int i, int j>
struct base {
  base()
  {
    std::cout << "i is " << i;
    std::cout << " j is " << j << std::endl;
  }
};

template <int... T>
struct wrapper {
  base<T...> a;
};

int main()
{
  wrapper<2, 3> x;
  return 0;
}

Knowing in advance that all template parameters of base are int, I use template <int...T> in the declaration of wrapper. This allows a limited flexibility, for instance I could define some default values for the template parameters of base, without modifying wrapper.

However, if base depends on an arbitray list of type and non-type template parameters, how can I pass the template parameters of wrapper to base?

For instance, if I know that all template parameters of base can be implicitly converted to int (without loss!), I could define wrapper as in the following program

#include <iostream>

template <int i, bool j>
struct base {
  base()
  {
    std::cout << "i is " << i;
    std::cout << " j is " << (j ? "true" : "false") << std::endl;
  }
};

template <int... T>
struct wrapper {
  base<T...> a;
};

int main()
{
  wrapper<2, true> x;
  return 0;
}

But if base depends at the same time on type and a non-type template parameters as in the following program, it is apparently not possible to simply pass the template parameters of wrapper to base:

#include <iostream>

template <class U, int i, int j>
struct base {
  base()
  {
    std::cout << "i is " << i;
    std::cout << " j is " << j << std::endl;
  }
};

template <class... T>
struct wrapper {
  base<T...> a;
};

int main()
{
  wrapper<int, 2, 3> x; // Error!
  return 0;
}

This program does not compile, because the compiler expects types for wrapper.

Is there a way to write a class wrapper that "pass" its template parameters to a member of type base, whatever they are?

The idea would be to have a generic code for wrapper which does not need to be modified if, say, the template signature of base changes.

like image 887
francesco Avatar asked Jun 27 '18 06:06

francesco


1 Answers

There is a solution to Your problem. It is not very elegant and requires specific approach but works in the cases You want:

template <class U, class i, class j>
struct base {
  base()
  {
    std::cout << "i is " << i::value;
    std::cout << " j is " << j::value << std::endl;
  }
};

template <class ...T>
struct wrapper {
  base<T...> a;
};

int main()
{
  wrapper<int, std::integral_constant<int, 2>, std::integral_constant<int, 3>> x; //no error now!
  return 0;
}

With C++17 it can be less verbose:

template<auto val>
using value_wrapper = std::integral_constant<decltype(val), val>;

int main()
{
  wrapper<int, value_wrapper<2>, value_wrapper<3>> x; //no error now!
  return 0;
}
like image 87
bartop Avatar answered Sep 27 '22 18:09

bartop