c++c++11variadic-templatesgcc4.9template-aliases

Unpacking parameter packs in template aliases


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.


Solution

  • 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.