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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With