`constexpr` 函数可以在 C++ 中前向声明吗?

16 c++ language-lawyer constexpr

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

考虑一个例子:

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

static_assert(bar() == 1);
Run Code Online (Sandbox Code Playgroud)

实际上所有编译器都支持,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);
Run Code Online (Sandbox Code Playgroud)

然后 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);
Run Code Online (Sandbox Code Playgroud)

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

rus*_*tyx 13

这是核心问题2166

Section : 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().