【问题标题】:Nested call of consteval functions with a reference argument带有引用参数的 consteval 函数的嵌套调用
【发布时间】:2022-01-06 22:27:20
【问题描述】:

下面的程序

template<class T>
consteval auto foo(const T&) {
   return 0;
}

template<class T>
consteval auto bar(const T& t) {
   auto n = foo(t);
   return n;
}

int main() {
   static_assert(foo("abc") == 0);
   static_assert(bar("abc") == 0);
}

在 GCC 中构建良好,但 Clang 用消息拒绝它:

error: call to consteval function 'foo<char[4]>' is not a constant expression
note: in instantiation of function template specialization 'bar<char[4]>' requested here
   static_assert(bar("abc") == 0);
note: function parameter 't' with unknown value cannot be used in a constant expression
   auto n = foo(t);

演示:https://gcc.godbolt.org/z/M6GPnYdqb

这是 Clang 中的一些错误吗?

【问题讨论】:

  • 注意:这种编译器差异不仅会出现在引用参数上,还会出现在指针上。
  • 惊喜,我将consteval auto bar(const T&amp; t) 更改为consteval auto bar(T t) 然后编译为clang。希望有人能澄清这一点。
  • @Evg:请注意,将consteval 替换为constexpr 有效Demo
  • 这是stackoverflow.com/questions/69166564 的副本但是,这个问题的措辞更好(更清晰的标题和更清晰的代码 sn-p)。此外,该副本的答案并不是特别有用,所以我将继续使用这个问题作为目标,一旦(如果)得到回答。

标签: c++ language-lawyer c++20 consteval


【解决方案1】:

这是一个clang错误。 gcc 和 msvc 是正确的接受它。

有两个相关的规则有问题:

所有立即调用必须是常量表达式。这来自[expr.const]/13

一个表达式或转换在一个立即函数上下文中如果它可能被评估并且:

  • 其最里面的封闭非块范围是立即函数的函数参数范围,或者
  • 其封闭语句由 consteval if 语句 ([stmt.if]) 的复合语句包围 ([stmt.pre])。

一个表达式或转换是一个立即调用,如果它是一个潜在评估的直接函数的显式或隐式调用并且不在立即函数上下文中。立即调用应该是一个常量表达式。

并且在常量表达式中不允许触摸未知引用(这是[expr.const]/5.13):

表达式 E 是核心常量表达式,除非 E 的求值遵循抽象机 ([intro.execution]) 的规则,将求值以下之一:[...]

  • 一个 id 表达式,它引用引用类型的变量或数据成员,除非该引用具有前面的初始化并且
    • 它可用于常量表达式或
    • 它的生命周期始于对 E 的评估;

有关后一条规则的更多信息,请参阅我在 the constexpr array size problemmy proposal to resolve this 上的帖子(希望适用于 C++23)。


好的,回到问题。 foo 显然没问题,它什么也没做。

bar 中,我们调用foo(t)。这不是一个常量表达式(因为t 是一个未知的引用),但是我们在一个直接的函数上下文中(因为barconsteval),所以foo(t) 不是一个常量并不重要表达。重要的是 bar("abc") 是一个常量表达式(因为 一个立即调用),并且我们在那里没有违反任何规则。这是非常微妙的,但是这里的引用t确实E的评估中开始了它的生命周期——因为E这里是调用bar("abc")不是 呼叫foo(t)

如果您标记bar constexpr 而不是consteval,那么其中的foo(t) 调用将成为立即调用,现在它不是常量表达式这一事实是相关的。在这种情况下,所有三个编译器都正确拒绝。

【讨论】:

    猜你喜欢
    • 2021-09-15
    • 2023-03-14
    • 2019-11-27
    • 1970-01-01
    • 2021-11-07
    • 2018-10-12
    • 2011-09-07
    • 2014-03-04
    相关资源
    最近更新 更多