http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57239
Bug ID: 57239 Summary: GCC cannot handle inner/nested class templates with non-type parameter packs that were declared in the outer/containing class Product: gcc Version: 4.8.1 Status: UNCONFIRMED Severity: major Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: scottbaldwin at gmail dot com GCC 4.7.2 and 4.8.x cannot handle inner/nested class templates with non-type parameter packs that were declared in the outer/containing class's template parameter list. This bug can result in either an "internal compile error", or even generate incorrect code (both are demonstrated), which is why I marked this bug as "major". I encountered this bug while trying to implement a helper template called is_instantiation_of__nontypes<> which is a non-type-parameter counterpart to the is_instantiation_of<> template described at [http://stackoverflow.com/questions/11251376/]. The demos below (one for compile-time error demo, one for run-time error demo) are implementations of this is_instantiation_of__nontypes<> template and work fine in clang, but in gcc 4.7.2 and 4.8.x fail to compile or produce incorrect results. These demos should compile "out of the box" as they have no dependencies other than the standard libraries. ---------------------------------------- compile-time error demo ---------------------------------------- // generic version of is_instantiation_of__nontypes<> (the template to check against is template-template parameter 'TT', taking "values" of the non-type parameter pack 'Ts...' declared in outer/containing class) template<bool BoolVal, char CharVal> struct Foo {}; template<typename... Ts> struct is_instantiation_of__nontypes { template<template<Ts...> class TT, typename T> struct check : std::false_type {}; template<template<Ts...> class TT, Ts... Args> struct check<TT, TT<Args...>> : std::true_type {}; }; int main() { using FooInstantiation = Foo<false, 'x'>; std::cout << ((is_instantiation_of__nontypes<bool, char>::check<Foo, FooInstantiation>::value) ? "yes" : "no") << endl; } --- This fails to compile in gcc 4.7.2/4.8.x with the following errors: [gcc 4.7.2]: make[1]: compiling [sandbox_cpp11.cpp] (gcc 4.7.2) sandbox_cpp11.cpp: In function ‘void gcc_bug_demo_3::_go_()’: sandbox_cpp11.cpp:122:88: error: type/value mismatch at argument 1 in template parameter list for ‘template<class ... Ts> template<template<template<Ts ...<anonymous> > class TT, class T> template<class ... Ts> template<Ts ...<anonymous> > class TT, class T> struct gcc_bug_demo_3::is_instantiation_of__nontypes<Ts>::check’ sandbox_cpp11.cpp:122:88: error: expected a template of type ‘template<class ... Ts> template<Ts ...<anonymous> > class TT’, got ‘template<bool BoolVal, char CharVal> struct gcc_bug_demo_3::Foo’ make[1]: *** [dbg-mt/sandbox_cpp11.o] Error 1 make: *** [objs] Error 2 [gcc 4.8.x]: make[1]: compiling [sandbox_cpp11.cpp] (gcc 4.8.x) sandbox_cpp11.cpp:116:27: error: ‘Ts ...’ is not a valid type for a template non-type parameter struct check<TT, TT<Args...>> : std::true_type {}; ^ sandbox_cpp11.cpp:116:30: error: template argument 2 is invalid struct check<TT, TT<Args...>> : std::true_type {}; ^ sandbox_cpp11.cpp: In function ‘void gcc_bug_demo_3::_go_()’: sandbox_cpp11.cpp:122:88: error: type/value mismatch at argument 1 in template parameter list for ‘template<class ... Ts> template<template<template<Ts ...<anonymous> > class TT, class T> template<class ... Ts> template<Ts ...<anonymous> > class TT, class T> struct gcc_bug_demo_3::is_instantiation_of__nontypes<Ts>::check’ std::cout << ((is_instantiation_of__nontypes<bool, char>::check<Foo, FooInstantiation>::value) ? "yes" : "no") << endl; ^ sandbox_cpp11.cpp:122:88: error: expected a template of type ‘template<class ... Ts> template<Ts ...<anonymous> > class TT’, got ‘template<bool BoolVal, char CharVal> struct gcc_bug_demo_3::Foo’ make[1]: *** [dbg-mt/sandbox_cpp11.o] Error 1 make: *** [objs] Error 2 4.8.x is slightly more verbose with the additional "error: ‘Ts ...’ is not a valid type for a template non-type parameter", which is incorrect since 'Ts...' was properly declared as a parameter pack in the containing class's template parameter list. In fact, if you simplify the code (by removing template-template parameter 'TT' and replacing it w/ hard-coded template class 'Foo') then it compiles fine, but has incorrect results at runtime, as demonstrated in the following code ... ---------------------------------------- run-time error demo ---------------------------------------- // simplified version of is_instantiation_of__nontypes<> (the template to check against is hardcoded as template 'Foo', instead of being template-template parameter 'TT') // compiles without error in all 4 compilers tested (gcc 4.7.2, 4.8.0, 4.8.1, and clang 3.3), but only has correct runtime results (output of "yes") when compiled with clang. template<bool BoolVal, char CharVal> struct Foo {}; template<typename... Ts> struct is_instantiation_of__nontypes // hard-coded for class template Foo { template<typename T> struct check : std::false_type {}; template<Ts... Args> struct check<Foo<Args...>> : std::true_type {}; }; int main() { using FooInstantiation = Foo<false, 'x'>; // the next line will output "yes" if the compiler has correct logic, or "no" otherwise std::cout << ((is_instantiation_of__nontypes<bool, char>::check<FooInstantiation>::value) ? "yes" : "no") << std::endl; } This demo outputs "yes" when compiled with clang (3.3), but outputs "no" when compiled with gcc (4.7.2 or 4.8.x).