Unpacking parameter packs in template aliases
Asked Answered
L

1

15

I run into a problem with unpacking variadic templates into a template alias.

The following code works with Clang 3.4 and GCC 4.8 but fails with GCC 4.9:

template <typename T, typename...>
using front_type = T;

template <typename... Ts>
struct foo
{
  using front = front_type<Ts...>;
};

GCC 4.9 complains:

test.cc:7:37: error: pack expansion argument for non-pack parameter 'T' of alias template 'template<class T, class ...> using front_type = T'
       using front = front_type<Ts...>;
                                     ^
test.cc:1:15: note: declared here
     template <typename T, typename...>
               ^

There exists a filed GCC bug (#59498), but is this supposed to fail? Here is some context from the C++ core language issue #1430, "pack expansion into fixed alias template parameter list":

Originally, a pack expansion could not expand into a fixed-length template parameter list, but this was changed in N2555. This works fine for most templates, but causes issues with alias templates.

In most cases, an alias template is transparent; when it's used in a template we can just substitute in the dependent template arguments. But this doesn't work if the template-id uses a pack expansion for non-variadic parameters. For example:

  template<class T, class U, class V>
  struct S {};

  template<class T, class V>
  using A = S<T, int, V>;

  template<class... Ts>
  void foo(A<Ts...>);

There is no way to express A<Ts...> in terms of S, so we need to hold onto the A until we have the Ts to substitute in, and therefore it needs to be handled in mangling.

Currently, EDG and Clang reject this testcase, complaining about too few template arguments for A. G++ did as well, but I thought that was a bug. However, on the ABI list John Spicer argued that it should be rejected.

Legend answered 26/6, 2014 at 14:50 Comment(4)
Can you move front_type outside of foo - they seem to be not related?Along
Yeah, good point @PiotrNycz. (It doesn't fix it, though.)Legend
I checked this modified code with gcc4.8 - looks it works.Along
"works with Clang 3.4" This is rejected by clang 3.5.0 however: error: pack expansion used as argument for non-pack parameter of alias templateHerr
A
12

It was reported in gcc4.9 bugzilla:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498

Minimal code to reproduce

template <typename T, typename ...>
using alias = T;

template <typename ...T>
using variadic_alias = alias<T...>;

using Fail = variadic_alias<int>;

int main() { }

From the explanation from gcc folks - it is not so obvious this is a real bug. This is still discussion held in gcc bugzilla and in DR 1430 (http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430) - summary in now in the question above.

Along answered 26/6, 2014 at 15:7 Comment(3)
It's reported as a bug but looking at the comments this seems to be by design.Chandelier
Yeah, it looks like this is supposed to fail? I edited the question with context from #1430Legend
@MatthiasVallentin I missed your comment - I will remove the duplicated content from my answer.Along

© 2022 - 2024 — McMap. All rights reserved.