template<typename T, T a, T... Params> struct max { static const T value = a > max<T, Params>::value ? a : max<T, Params>::value; }; template<typename T, T a, T b> struct max<T, a, b> { static const T value = a > b ? a : b; }; static const int value1 = max< int, 1, 2>::value; static const int value2 = max< int, 1, 3, 5>::value; As the initialization for value1 is accepted as valid, that should be also the case for value2. But g++ fails with the following error: g++-4.3.0 -std=c++0x -c -o test.o test.cpp test.cpp: In instantiation of 'const int max<int, 1, 3, 5>::value': test.cpp:14: instantiated from here test.cpp:4: error: 'max<int, 1, 3, 5>::value' cannot be initialized by a non-constant expression when being declared g++ Version is "gcc version 4.3.0 20071123 (experimental) (GCC)"
Doug, can you have a look? Adding the missing definitions moves the error to link-time but it persists: something seems indeed fishy in the front-end code for static constant members vs variadic templates...
value = MAX_EXPR <(int) value, 1> Which means we did not "inline" the value of the other value. Confirmed.
another testcase: template<template<typename... T> class Comp, typename... T> void f( T... Value) { static_assert( Comp<T>::value > 0, "" ); } template <typename... T> struct Foo { static const int value=1; }; int main() { f<Foo>( 2 ); }
There are some problems with the example code. For example, the expression max<T, Params> does not expand the parameter pack "Params". The compiler should have warned you about this, both in this case and in the static_assert case.
for #3, using static_assert( Comp<T...>::value > 0, "" ); makes it work. using max<T, Params...> for #1 leads gcc to an error: "cannot expand 'Params ...' into a fixed-length argument list" updated testcase: template<typename T, T a, T... Params> struct max { static const T value = a > max<T, Params...>::value ? a : max<T, Params...>::value; }; template<typename T, T a, T b> struct max<T, a, b> { static const T value = a > b ? a : b; }; static const int value1 = max< int, 1, 2>::value; static const int value2 = max< int, 1, 3, 5>::value; If there are no more errors in thats code, this is a rejects-valid, not an error-recovery
Subject: Bug 34219 Author: dgregor Date: Tue Jan 29 13:59:59 2008 New Revision: 131938 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131938 Log: 2008-01-29 Douglas Gregor <doug.gregor@gmail.com> PR c++/34055 PR c++/34103 PR c++/34219 PR c++/34606 PR c++/34753 PR c++/34754 PR c++/34755 PR c++/34919 PR c++/34961 * c-pretty-print.c (pp_c_type_qualifier_list): Don't try to print qualifiers for an ERROR_MARK_NODE or a NULL_TREE. 2008-01-29 Douglas Gregor <doug.gregor@gmail.com> PR c++/34055 PR c++/34103 PR c++/34219 PR c++/34606 PR c++/34753 PR c++/34754 PR c++/34755 PR c++/34919 PR c++/34961 * typeck.c (check_return_expr): Tweak call to check_for_bare_parameter_packs. * class.c (add_method): Be careful with error_mark_nodes. * cp-tree.h (check_for_bare_parameter_packs): Remove "*" from signature. * pt.c (struct find_parameter_pack_data): Remove SET_PACKS_TO_ERROR. (find_parameter_packs_r): Don't use SET_PACKS_TO_ERROR. (uses_parameter_packs): Don't set SET_PACKS_TO_ERROR. (make_pack_expansion): Ditto. (check_for_bare_parameter_packs): Parameter is now a tree, not a tree*. (process_template_parm): Tweak call to check_for_bare_parameter_packs. (push_template_decl_real): Tweak calls to check_for_bare_parameter_packs. If bare parameter packs are found in the list of exceptions, clear out that list after giving an error. * semantics.c (finish_cond): Tweak call to check_for_bare_parameter_packs. (finish_expr_stmt): Ditto. (finish_for_expr): Ditto. (finish_switch_cond): Ditto. (finish_mem_initializers): Ditto. (finish_member_declaration): Ditto. (finish_static_assert): Check for bare parameter packs in the condition. * decl2.c (cplus_decl_attributes): Check for bare parameter packs in the attributes of a declaration. * parser.c (cp_parser_using_declaration): Tweak call to check_for_bare_parameter_packs. (cp_parser_base_clause): Ditto. 2008-01-29 Douglas Gregor <doug.gregor@gmail.com> PR c++/34055 PR c++/34103 PR c++/34219 PR c++/34606 PR c++/34753 PR c++/34754 PR c++/34755 PR c++/34919 PR c++/34961 * g++.dg/cpp0x/vt-34219-2.C: New. * g++.dg/cpp0x/pr32126.C: Tweak expected error messages. * g++.dg/cpp0x/vt-34961.C: New. * g++.dg/cpp0x/vt-34055.C: Tweak error messages; add new test cases from the re-opened PR. * g++.dg/cpp0x/vt-34753.C: New. * g++.dg/cpp0x/vt-34919.C: New. * g++.dg/cpp0x/vt-34754.C: New. * g++.dg/cpp0x/vt-34606.C: New. * g++.dg/cpp0x/vt-34219.C: New. * g++.dg/cpp0x/pr32125.C: Tweak expected error messages. * g++.dg/cpp0x/vt-34755.C: New. * g++.dg/cpp0x/pr31438.C: Ditto. * g++.dg/cpp0x/variadic81.C: Ditto. Added: trunk/gcc/testsuite/g++.dg/cpp0x/vt-34219-2.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34219.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34606.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34753.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34754.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34755.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34919.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34961.C Modified: trunk/gcc/ChangeLog trunk/gcc/c-pretty-print.c trunk/gcc/cp/ChangeLog trunk/gcc/cp/class.c trunk/gcc/cp/cp-tree.h trunk/gcc/cp/decl.c trunk/gcc/cp/decl2.c trunk/gcc/cp/parser.c trunk/gcc/cp/pt.c trunk/gcc/cp/semantics.c trunk/gcc/cp/typeck.c trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/cpp0x/pr31438.C trunk/gcc/testsuite/g++.dg/cpp0x/pr32125.C trunk/gcc/testsuite/g++.dg/cpp0x/pr32126.C trunk/gcc/testsuite/g++.dg/cpp0x/variadic81.C trunk/gcc/testsuite/g++.dg/cpp0x/vt-34055.C
Actually, I don't know whether max<T, Params...> is valid or not. My inclination is that it is invalid, because when Params is empty, it becomes an invalid specialization max<T>. (This happens, for example, if we try to compute max<int, 17>::value. However, it's not clear to me whether the wording in the C++0x working draft supports that view or not. We say this about function parameter pack arguments not matching to normal function parameters in partial ordering, but we don't talk about this case at all. I am going to submit an issue to the C++ Core Working Group to get this clarified. Until then, I'm going to suspend this bug: then we'll either close it (if the committee deems this code ill-formed) or re-open it to be fixed in GCC 4.4.
Fixed on mainline
This was fixed long ago.