首页 > 解决方案 > `constexpr` 函数可以在 C++ 中前向声明吗?

问题描述

我可以constexpr在给出定义之前在 C++ 中声明一个函数吗?

考虑一个例子:

constexpr int foo(int);
constexpr int bar() { return foo(42); }
constexpr int foo(int) { return 1; }

static_assert(bar() == 1);

它实际上是所有编译器都支持的,demo:https ://gcc.godbolt.org/z/o4PThejso

但是,如果foo在模板中转换函数:

constexpr int foo(auto);
constexpr int bar() { return foo(42); }
constexpr int foo(auto) { return 1; }

static_assert(bar() == 1);

然后 Clang 拒绝接受它,说https://gcc.godbolt.org/z/EG7cG9KTM

<source>:5:15: error: static_assert expression is not an integral constant expression
static_assert(bar() == 1);
              ^~~~~~~~~~
<source>:2:30: note: undefined function 'foo<int>' cannot be used in a constant expression
constexpr int bar() { return foo(42); }
                             ^
<source>:5:15: note: in call to 'bar()'
static_assert(bar() == 1);

它仍然是有效的 C++ 代码还是 Clang 错误?

标签: c++language-lawyerconstexpr

解决方案


这是核心问题2166

7.7 节 [expr.const] 状态:起草 提交人:Howard Hinnant 日期:2015-08-05

根据 7.7 [expr.const] bullet 2.3,表达式是常量表达式,除非(除其他原因外)它会计算

调用未定义的 constexpr 函数或未定义的 constexpr 构造函数;

这没有解决必须定义 constexpr 函数的点的问题。为了允许相互递归的 constexpr 函数,其目的是必须在最终导致调用的最外层评估之前定义该函数,但这没有明确说明。

换句话说,标准在这种情况下并不清楚,所以每个编译器都可以自由地接受或拒绝它认为合适的代码。

在 Clang 的情况下,auto通过将函数转换为模板来实现参数。这使得编译器更难维护 constexpr 上下文。这并不是说不可能实现(毕竟 GCC 没有问题),直到 2166 解决它才不是 bug。

同时,您可以通过制作bar()模板或autofoo().


推荐阅读