下面的代码或godbolt上的代码用gcc和MSVC编译,但失败了,并发出叮当声。我不知道是否/在标准中禁止它。在我看来,它应该得到支持。
那么谁是正确的,clang还是gcc/MSVC?谢谢!
#include <type_traits>
void foo() {
static_assert(decltype([_=std::declval<int>()]() consteval noexcept { // clang error: declval() must not be used
if constexpr (std::is_integral<decltype(_)>::value) {
return std::bool_constant<true>();
} else {
return std::bool_constant<false>();
}
}())::value);
}
=====================编辑===========
该示例可扩展为以下3种情况或godbolt:
1.作为lambda调用参数:通过clang/gcc/MSVC确认
1.作为λ捕获:gcc/MSVC正常,叮当声错误
1.在lambda主体中:clang/gcc/MSVC出错
因此,似乎很清楚,它在lambda主体中是不法律的,但在外部作为调用方参数是合法不清楚是否允许在捕获列表中使用
#include <type_traits>
auto foo_lambda_argument() {
return decltype([](auto _) noexcept {
return std::bool_constant<std::is_integral<decltype(_)>::value>();
}(std::declval<int>()))::value; // OK with clang/gcc/MSVC
}
auto foo_capture_list() {
return decltype([_=std::declval<int>()]() noexcept { // OK with gcc/MSVC; clang error: declval() must not be used
return std::bool_constant<std::is_integral<decltype(_)>::value>();
}())::value;
}
auto foo_lambda_body() {
return decltype([]() noexcept {
auto _=std::declval<int>(); // clang/gcc/MSVC error
return std::bool_constant<std::is_integral<decltype(_)>::value>();
}())::value;
}
1条答案
按热度按时间dxpyg8gm1#
我不完全确定这是如何工作的,但这里是我的尝试在一个解决方案:
根据[intro.execution]/3.3,init-capture 的初始化器是lambda表达式的立即子表达式。然而,所列出的项目中没有一个使表达式在lambda的主体子表达式中。
未赋值的操作数是非潜在求值的表达式。但只有它们的子表达式也是非潜在求值的表达式。(请参阅[basic.def.odr]/2)
如果一个函数是由一个可能计算的表达式命名的,或者在一些与这里无关的特殊情况下,则该函数是odr使用的。
所以
std::declval
在init-capture初始化器中应该是好的,就像你的第2点一样。在第1点中也是可以的,因为函数参数是函数调用表达式的子表达式,组成了整个未求值的操作数。
第3点是不行的,因为即使lambda表达式出现在未求值的操作数中,lambda主体中的表达式也可能被求值。
我对上述推理的一个担忧是,[exp.prim.lambda.capture]/6指定了一个init-capture,其行为就像用给定的初始化器声明一个变量,然后捕获它。我不确定这在哪里适合上述推理(声明不能是子表达式),以及它是否算作odr-use。