geza
geza

Reputation: 29970

Workaround for passing parameter pack to alias templates (which have non-pack parameters)

Look at this example:

template <typename A>
struct Foo1 {};

template <typename A, typename B>
struct Foo2 {};

struct Bar1 {
    template <typename A>
    using Foo = Foo1<A>;
};

struct Bar2 {
    template <typename A, typename B>
    using Foo = Foo2<A, B>;
};

template <typename BAR>
struct Something {
    template <typename ...P>
    void func(typename BAR::template Foo<P...> foo) {
    } 
};

I'd like to achieve: if Something is specialized with Bar1, then I'd like to have a template function func, which is:

   template <typename A>
   void func(Foo1<A> foo)

and if Something is specialized with Bar2, then func should be:

   template <typename A, typename B>
   void func(Foo2<A, B> foo)

However, this straightforward approach doesn't work, because clang complains (you need to instantiate Something<BarX> to make clang to report this error):

error: pack expansion used as argument for non-pack parameter of alias template void func(typename BAR::template Foo<P...> foo) {

So it seems that alias templates are not 100% transparent (I found some discussion about this: CWG 1430, that this is by design).

Are the any workarounds for this problem?

(gcc compiles this code, but according to CWG 1430, this might be unintended)

Upvotes: 3

Views: 235

Answers (1)

Jarod42
Jarod42

Reputation: 218088

Workaround is to make the alias variadic:

struct Bar1 {
    template <typename... Ts>
    using Foo = Foo1<Ts...>;
};

struct Bar2 {
    template <typename... Ts>
    using Foo = Foo2<Ts...>;
};

Demo

Upvotes: 3

Related Questions