You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

函数参数用作常量表达式:GCC与Clang编译差异探究

Which Compiler's Behavior Follows the C++ Standard Here?

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:12:26