函数参数用作常量表达式:GCC与Clang编译差异探究
Let's break down this scenario clearly, starting with the code that's causing the discrepancy:
template <bool> struct B { }; template <typename T> constexpr bool pred(T t) { return true; } template <typename T> auto f(T t) -> decltype(B<pred(t)>{}) { }
Compiler Behavior Breakdown
- Clang++ (trunk) successfully compiles this code.
- G++ (trunk) fails to compile, with the following error output:
src:7:34: error: template argument 1 is invalid auto f(T t) -> decltype(B<pred(t)>{}) { } ^ src:7:34: error: template argument 1 is invalid src:7:34: error: template argument 1 is invalid src:7:34: error: template argument 1 is invalid src:7:34: error: template argument 1 is invalid src:7:34: error: template argument 1 is invalid src:7:25: error: invalid template-id auto f(T t) -> decltype(B<pred(t)>{}) { } ^ src:7:36: error: class template argument deduction failed: auto f(T t) -> decltype(B<pred(t)>{}) { } ^ src:7:36: error: no matching function for call to 'B()' src:1:24: note: candidate: 'template<bool <anonymous> > B()-> B<<anonymous> >' template <bool> struct B { }; ^ src:1:24: note: template argument deduction/substitution failed: src:7:36: note: couldn't deduce template parameter '<anonymous>' auto f(T t) -> decltype(B<pred(t)>{}) { } ^
The Standard's Take on This
The core issue boils down to C++'s rules for non-type template arguments: when you pass an expression as a non-type template parameter (like the bool we're passing to B), that expression must be a converted constant expression of the parameter's type.
In the original code, pred(t) relies on t—a function parameter of f. Even though pred is marked constexpr, t is a runtime value whose concrete value isn't known at compile time when we instantiate f. That means pred(t) can't be evaluated as a constant expression, making it an invalid argument for B's template parameter.
GCC is correctly enforcing this standard rule by rejecting the code. Clang's acceptance of the original code is either an extension or lenient non-compliance—it doesn't align with the C++ standard here.
The Compliant Fix
Changing the trailing return type to use pred(T{}) instead of pred(t) resolves the issue for both compilers:
template <typename T> auto f(T t) -> decltype(B<pred(T{})>{}) { }
Here, T{} is a compile-time evaluable prvalue (assuming T can be default-constructed in a constant-expression context), so pred(T{}) qualifies as a valid converted constant expression for B's bool template parameter. This version is fully standard-compliant, hence why both compilers accept it.
内容的提问来源于stack exchange,提问作者Vittorio Romeo

