I want to pass the variadic template parameters (a set of integers) of an derived class to another templated class. I can not modify the second class because its part of an libary.
I already figured out how I can store this parameters at compile time (e.g. constant array or integer_sequence) but I have no clue how to pass these structures to the library class. The solution might be obvious but I'm currently lost in all the possibilities to handle this variadic stuff.
I tried to build a simple example to explain my problem better:
// Example program
#include <iostream>
#include <array>
#include <utility>
// this class has some compile time paramters
template <int... N>
class BaseClass
{
public:
BaseClass(){};
~BaseClass(){};
//one idea to store the parameters using a compile time array
static constexpr std::array<int, sizeof...(N)> _N = {{N...}};
//another idea using a integer sequence type
using _Ni = std::integer_sequence<int, N...>;
};
// this special case of BaseClass hast the parameter 5,6,7,8
class SpecialClass:public BaseClass<5,6,7,8>
{
public:
SpecialClass(){};
~SpecialClass(){};
};
// this class is fixed and can not be modified because it's part of an libary
template <int... N>
class Printer
{
public:
Printer(){};
~Printer(){};
// it can (for example) print its template parameters
void print()
{
int dummy[sizeof...(N)] = { (std::cout << N, 0)... };
}
};
int main()
{
// this obviously works
Printer <1,2,3,4> TestPrinter;
TestPrinter.print();
// this works not
Printer <SpecialClass::_N> TestPrinterSpecialArray;
TestPrinterSpecialArray.print();
// this also works not
Printer <SpecialClass::_Ni> TestPrinterSpecialSequence;
TestPrinterSpecialSequence.print();
return 0;
}
You can write a helper function that unpacks std::integer_sequence
,
template<int... is>
auto make_printer_impl(std::integer_sequence<int, is...>)
{
Printer<is...> printer;
return printer;
}
template<class T>
auto make_printer()
{
return make_printer_impl(typename T::_Ni{});
}
and then use it like this:
auto TestPrinterSpecialSequence = make_printer<SpecialClass>();
TestPrinterSpecialSequence.print();
You can do the similar thing for std::array
member:
template<class T, std::size_t... is>
auto make_printer_impl(std::index_sequence<is...>)
{
Printer<T::_N[is]...> printer;
return printer;
}
template<class T>
auto make_printer()
{
return make_printer_impl<T>(std::make_index_sequence<T::_N.size()>{});
}
Also note that identifiers that begin with an underscore followed by an uppercase letter are reserved. Their usage leads to the undefined behavior. Don't use them.
You can create helper to do that:
template <typename T, template <std::size_t...> class Other> struct remap;
template <template <std::size_t...> class Orig,
std::size_t... Is,
template <std::size_t...> class Other>
struct remap<Orig<Is...>, Other>
{
using type = Other<Is...>;
};
template <typename T, template <std::size_t...> class Other>
using remap_t = typename remap<T, Other>::type;
And then
using SpecialClass = BaseClass<5,6,7,8>;
remap_t<SpecialClass, Printer> TestPrinterSpecialSequence; // Printer <5, 6, 7, 8>
TestPrinterSpecialSequence.print();
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