The following test case is failing: #include <cstdio> constexpr std::size_t fibonacci(std::size_t val) { return (val <= 2) ? 1 : fibonacci(val - 1) + fibonacci(val - 2); } template <typename Function> struct Defer { constexpr Defer(const Function func_) : func(func_) { } const Function func; template <typename... Args> constexpr auto operator () (const Args&... args) -> decltype(func(args...)) { return func(args...); } }; template <typename Function> constexpr Defer<Function> make_deferred(const Function f) { return Defer<Function>(f); } int main(int argc, char* argv[]) { constexpr auto deferred = make_deferred(&fibonacci); static_assert(deferred(25) == 75025, "Static fibonacci call failed"); } src/main.cpp: In function 'int main(int, char**)': src/main.cpp:151:3: error: non-constant condition for static assertion src/main.cpp:151:28: in constexpr expansion of 'deferred.Defer<Function>::operator()<{int}>((* &25))' src/main.cpp:140:24: error: expression 'fibonacci' does not designate a constexpr function test.make:129: recipe for target `obj/Debug/main.o' failed make[1]: *** [obj/Debug/main.o] Error 1 makefile:16: recipe for target `test' failed make: *** [test] Error 2 Based on my reading of the standard, this should be allowed behavior, and works as expected with clang 3.1 (152539). Note that the following behavior also fails similarly: int main(int argc, char* argv[]) { constexpr auto deferred = make_deferred(&fibonacci); constexpr auto func = deferred.func; constexpr auto val = func(25); } src/main.cpp: In function 'int main(int, char**)': src/main.cpp:152:31: error: expression 'fibonacci' does not designate a constexpr function Whereas this succeeds: int main(int argc, char* argv[]) { constexpr auto func = &fibonacci; static_assert(func(25) == 75025, "Static fibonacci call failed"); }
(In reply to comment #0) [..] > Based on my reading of the standard, this should be allowed behavior, and > works as expected with clang 3.1 (152539). I agree that this should work, this was the clear intention for the core language defect http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1193 I tried to break down the example to understand what's going wrong and here is one simpler example: //--------------- constexpr bool is_negative(int x) { return x < 0; } struct Defer { #if 0 typedef bool (*Function)(int); Function func; constexpr Defer(Function func) : func(func) {} #else bool (*func)(int); constexpr Defer(bool (* func)(int)) : func(func) {} #endif template<class... Args> constexpr auto operator()(const Args&... args) -> decltype(func(args...)) { return func(args...); } }; template<class Function> constexpr Defer make_deferred(Function func) { return Defer(func); } int main() { constexpr Defer deferred(make_deferred(is_negative)); static_assert(deferred(-2), "Error"); } //--------------- As written, this example is well-formed. But once we change the pre-processor directive "#if 0" to "#if 1", we have a similar error. It seems that after introduction of the typedef for the function pointer type gcc no longer attempts to consider the track the constness. It is possible to construct an even simpler example. Consider the code example from CWG defect 1193 again: constexpr bool is_negative(int x) { return x < 0; } constexpr bool check(int x, bool (*p)(int)) { return p(x); } static_assert(check(-2, is_negative), "Error"); gcc accepts it as it should. Now lets introduce a typedef for the function pointer used in check: constexpr bool is_negative(int x) { return x < 0; } typedef bool (*Function)(int); constexpr bool check(int x, Function p) { return p(x); } static_assert(check(-2, is_negative), "Error"); Now we get a similar error as in your example: "4|error: non-constant condition for static assertion| 4| in constexpr expansion of 'check(-2, is_negative)'| 3|error: expression 'is_negative' does not designate a constexpr function" The template parameter in your example has similar effects as a typedef. Both use cases should not invalidate the constexpr character.
Hello everyone, Im ay have an issue related to this issue, if that can help: #include <iostream> struct A { void f(int i) { std::cout << "f " << i << " " << _i << std::endl; } void f2(int i) { std::cout << "f2 " << i << " " << _i << std::endl; } int _i; }; template <typename F, F f> struct class_f { typedef F f_type; static constexpr f_type f_value = f; static constexpr f_type get() { return f; } }; int main() { typedef class_f<decltype(&A::f), &A::f> ff_t; // This does not compile class_f<ff_t::f_type, ff_t::f_value> ff; // This does not compile either class_f<ff_t::f_type, static_cast<ff_t::f_type>(&A::f)> ff2; // This does class_f<ff_t::f_type, &A::f> ff_works; } It looks like using a function pointer that has been "instantiated" as an "f_type" makes the compilation fails. here is the output of g++-4.7 with the first "failing" tests : $ g++-4.7 -std=c++0x ftempl.cpp ftempl.cpp: In function ‘int main()’: ftempl.cpp:24:37: error: could not convert template argument ‘class_f<void (A::*)(int), &A::f>::f_value’ to ‘void (A::*)(int)’ ftempl.cpp:24:41: error: invalid type in declaration before ‘;’ token $ g++-4.7 --version g++-4.7 (Debian 4.7.0-8) 4.7.0
Author: paolo Date: Wed Aug 27 17:03:34 2014 New Revision: 214579 URL: https://gcc.gnu.org/viewcvs?rev=214579&root=gcc&view=rev Log: /cp 2014-08-27 Paolo Carlini <paolo.carlini@oracle.com> PR c++/52892 * semantics.c (cxx_eval_call_expression): Use STRIP_NOPS on the result of cxx_eval_constant_expression. /testsuite 2014-08-27 Paolo Carlini <paolo.carlini@oracle.com> PR c++/52892 * g++.dg/cpp0x/constexpr-52892-1.C: New. * g++.dg/cpp0x/constexpr-52892-2.C: Likewise. * g++.dg/cpp0x/constexpr-52282-1.C: Likewise. Added: trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-52282-1.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-52892-1.C trunk/gcc/testsuite/g++.dg/cpp0x/constexpr-52892-2.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/semantics.c trunk/gcc/testsuite/ChangeLog
Fixed.