【发布时间】:2021-11-08 16:01:15
【问题描述】:
编译时关键字的规则:constexpr、consteval 和 constinit 的定义似乎足够好,编译器会在您误用标签时发出警告。
编译器(很像内联)可以在所有地方应用规则来确定代码是否实际上可以应用编译时关键字之一,并且根据语言规范强制应用,这是有道理的,尽可能多地编译,就像应用了编译时关键字一样。
或者,至少,如果将编译时关键字应用于函数,并且应用了正确的编译时关键字,则代码将符合条件。编译该函数,就好像所有调用的函数都有正确的编译时关键字一样。
这是一个简单的例子:
#include <tuple>
consteval std::tuple<int, int> init1(int x, int y)
{
return {x,y};
}
std::tuple<int, int>& foo1()
{
static constinit std::tuple<int, int> x=init1(1,2);
return x;
}
std::tuple<int, int> init2(int x, int y)
{
return {x,y};
}
std::tuple<int, int>& foo2()
{
static std::tuple<int, int> x=init2(1,2);
return x;
}
static std::tuple<int, int> x3=init2(1,2);
std::tuple<int, int>& foo3()
{
return x3;
}
在这里查看:https://godbolt.org/z/KrzGfnEo7
请注意,init1/foo1 完全使用编译时关键字指定,并且不需要保护变量,因为它已完全初始化(不仅仅是 0 填充)。
问题是为什么编译器在 init2/foo2 或 x3/foo3 的情况下不做同样的事情?或者更确切地说,为什么允许编译器在编译时不完全初始化。
需要编辑(根据评论)请参阅 (Why do we need to mark functions as constexpr?) constexpr。我更关心consteval 和constinit 的情况。是否可以修改规范以要求在编译时尝试解析代码并且不会因为缺少constexpr 而失败?这将允许接口合约根据相关问题仅使用 constexpr。
【问题讨论】:
-
你在问为什么
constexpr没有被自动应用? (阅读stackoverflow.com/q/14472359/103167)或者编译器是否可以对不使用constexpr的代码执行编译时优化? (可以。) -
是的,我明白,因为 constexpr 是可选的。我更关心我应用 consteval 或 constinit 并且编译器可以允许它的地方,而与 constexpr 等的存在无关,如果不清楚,抱歉。我会看看是否可以进行编辑以使其更清晰。
-
允许编译器应用任何优化,只要您无法区分。当一个函数可以在编译时评估时,为什么不应该呢?见stackoverflow.com/questions/15718262/…。
-
问题不是“编译器可以吗?”,而是“为什么不需要编译器?”
-
@GlennTeitelbaum:“是否可以修改规范以要求在编译时尝试解析代码并且不会因为缺少
constexpr而失败?”实现质量的问题,而不是语言规范。
标签: c++ language-lawyer c++20