4

I would like to achieve this:

Foo<int, 5, double, 7> foo_1;
Foo<char, 7> foo_2;

foo_1.Foo<int>::value[4] = 1;
foo_2.Foo<char>::value[1] = 'x';

(This is an oversimplified example, Foo would do much more than this.)

How can I do that with variadic templates?

TLDR;

I know that variadic templates can be used in this way if exclusively types or non-types are used:

template <typename ...T>
struct Foo;

template<typename T, typename ...Args>
struct Foo<T, Args...> : Foo<T>, Foo<Args...> {
    Foo(T t, Args... args) : Foo<T>(t), Foo<Args...>(args...) { }
};

template<typename T>
struct Foo<T> {
    T value;

    Foo<T>(T v) : value(v) {}
};

Foo<int, double, char> f(7, 88.1, 'x');
f.Foo<double>::value = 5;

But I do not whether it is possible to pair and mix type and non-type template arguments using variadic templates.

2
  • It feels like you are trying to reinvent tuple Commented May 22, 2021 at 19:52
  • @Ranoiaetep This is an oversimplified example... Commented May 22, 2021 at 20:05

3 Answers 3

6

It's not possible. You'll have to settle for one of the following:

Foo<Bar<int, 5>, Bar<double, 7>> foo_1;
Foo<int, Bar<5>, double, Bar<7>> foo_1;
// ...?

If the values are always integral, you could also try this:

Foo<int[5], double[7]> foo_1;

And then extract elemenet types & extents from each argument.

Sign up to request clarification or add additional context in comments.

2 Comments

For your first example, Bar could be std::array. For your second it's almost std::integral_constant except the type would have to be hard-coded.
@o11c For the second example you could also use a class with an auto template parameter.
4

But I do not whether it is possible to pair and mix type and non-type template arguments using variadic templates.

Not with an alternate variadic template. But you can wrap couples of types/sizes.

Suppose you have a Bar class as follows

template <typename T, std::size_t N>
struct Bar
 { std::array<T, N>  value; };

using class specialization you can have a variadic Bar so a variadic list of types and a variadic list of sizes

template <typename...>
struct Foo;

template <typename ... Ts, std::size_t ... Ns>
struct Foo<Bar<Ts, Ns>...> : public Bar<Ts, Ns>...
 { };

You can use it as follows

   Foo<Bar<int, 5>, Bar<double, 7>> foo_1;
   Foo<Bar<char, 7>> foo_2;

   foo_1.Bar<int, 5>::value[4] = 1;
   foo_2.Bar<char, 7>::value[1] = 'x';

The following is a full compiling example

#include <array>

template <typename T, std::size_t N>
struct Bar
 { std::array<T, N>  value; };

template <typename...>
struct Foo;

template <typename ... Ts, std::size_t ... Ns>
struct Foo<Bar<Ts, Ns>...> : public Bar<Ts, Ns>...
 {
 };

int main ()
 {
   Foo<Bar<int, 5>, Bar<double, 7>> foo_1;
   Foo<Bar<char, 7>> foo_2;

   foo_1.Bar<int, 5>::value[4] = 1;
   foo_2.Bar<char, 7>::value[1] = 'x';
 }

3 Comments

Would template <typename ... Ts, std::size_t ... Ns> work? I tried earlier but MSVC compiler complains that the variadic part must be the last one in the template argument list.
@TiborTakács Note the way Ts and Ns are used. They were used together here as Bar<Ts, Ns>...
@TiborTakács - Observe how are used: Bar<Ts, Ns>.... They are wrapped inside Bar; this way you have a variadic Bar so you can have two parallelized (but also three, or four, etc.) variadic lists of the same length. I've added a full compiling example that compile with both g++ and clang++
0

You can pass array type as typename, example in your case will become:

Foo<std::array<int, 5>, std::array<double, 7> > foo_1(
    std::array<int, 5>{0,0,0,0,0},
    std::array<double, 7>{0,0,0,0,0,0,0});

foo_1.Foo<std::array<int, 5>>::value[4] = 1;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.