我如何启用constexpr ' missing return statement '活动错误而没有警告?



假设我有constexpr数据集。我主要在编译时使用它,它为可能影响未来constexpr语句的设置存储数据。string_view允许我命名这些设置并轻松搜索它们:


struct data {
std::string_view name;
int value;
};
constexpr auto data_set = std::array{
data{"foo", 100},
data{"bar", 200},
};

,这是constexpr函数,允许我查找数据点并返回它们的值:

constexpr int get_data(std::string_view search) {
for (auto& data : data_set) {
if (data.name == search) {
return data.value;
}
}
}

当我用正确的字符串名和不正确的字符串名调用这个函数时,工作得很好。因为如果没有找到name,则该函数没有返回语句,因此无法初始化constexpr值:

int main() {
constexpr auto foo = get_data("foo");
constexpr auto foo2 = get_data("foo2"); //Error C2131: expression did not evaluate to a constant
}

和我的IDE (Visual Studio)甚至给了我一个很好的可见的活动错误:

Error (active)  E0028   expression must have a constant value
然而,当使用这个并对它进行非constexpr调用时,我总是得到警告
warning C4715: 'get_data': not all control paths return a value

,显然我不能添加一个默认的返回值,因为那会破坏"constexpr失败,如果invalidate "目的,但我仍然希望能够用它初始化运行时变量(因为搜索string_view在编译时仍然是已知的,使其安全)。


那么是否有一种方法可以保留无效输入的错误,但可以删除错误?对于不返回任何值的函数,也可以使用这种方法吗?

consteval将启用此行为。这样一来,任何以这种方式标记的函数都必须在编译时求值。这也将删除警告,因为如果它没有正确计算,它将被错误取代。

consteval int get_data(std::string_view search) {
for (auto& data : data_set) {
if (data.name == search) {
return data.value;
}
}
}
int main() {
constexpr auto foo = get_data("foo");
constexpr auto foo2 = get_data("foo2");
}

"foo2"行导致C2131和活动错误E3133:

Error   C2131   expression did not evaluate to a constant
Error (active)  E3133   call to consteval function "get_data" did not produce a valid constant expression   

你仍然可以使用它来初始化运行时变量:

auto bar = get_data("bar");

作为get_data可以在编译时求值,基本上被data{ "bar", 200 }.value;200取代。


现在consteval将使纯运行时调用不再工作(如从std::cin输入或从文件中读取搜索项),但这是期望的行为,因为如果输入无效,理论上可能导致未指定的分支。


你也可以使这个工作的函数返回什么?

可以在被到达的分支中添加无效的语句。例如1 / 0:

consteval void check_data(std::string_view search) {
for (auto& data : data_set) {
if (data.name == search) {
return;
}
}
auto invalid = 1 / 0;
}
int main() {
check_data("foo");
check_data("bar");
check_data("bar2"); //E3133 active error
}

@GoswinvonBrederlow建议抛出异常,这也工作得很好,在我看来甚至比1 / 0更干净:

consteval auto get_data(std::string_view search) {
for (auto& data : data_set) {
if (data.name == search) {
return data.value;
}
}
throw std::exception("fail");
}
consteval void check_data(std::string_view search) {
for (auto& data : data_set) {
if (data.name == search) {
return;
}
}
throw std::exception("fail");
}
int main() {
constexpr auto foo = get_data("foo");
constexpr auto foo2 = get_data("foo2"); //E3133 active error
auto bar2 = get_data("foo2");  //E3133 active error
check_data("foo");
check_data("foo2"); //E3133 active error
}

我知道可以有许多优雅的解决方案,但我建议的是像在函数末尾添加无条件返回一样简单。

constexpr int get_data(std::string_view search) {
for (auto& data : data_set) {
if (data.name == search) {
return data.value;
}
}
return -1;
}

查看运行情况:https://godbolt.org/z/zKx7M3j8a

最新更新