lambda 在常量表达式中的使用
Usage of lambda in constant expression
取下面的代码:
template <typename T, typename U>
constexpr bool can_represent(U&& w) noexcept
{
return [] (auto&& x) {
try {
return T(std::forward<U>(x)) == std::forward<U>(x);
} catch(...) {
return false;
}
} (std::forward<U>(w));
}
我在常量表达式(模板)中使用这个函数。
gcc
编译没有问题。 clang
和MSVC
没有,感叹函数没有得到常量表达式。
的确,gcc
也没有立即接受;它挂在 try
上,通常在 constexpr
函数中是不允许的。这就是为什么我必须使用立即调用的 lambda 表达式的原因。但是,现在它可以工作了,考虑到它只适用于 gcc
我很困惑。
哪个编译器是正确的?
是否有 lambda 的 属性 允许它在 constexpr
上下文中工作,或者这是某种非标准 gcc
扩展?
[我使用 godbolt 与 clang
和 MSVC
一起编译,因为我的机器上有 gcc 8.1.0
]
[gcc] was getting hung up on the try
, that normally wouldn't be allowed in a constexpr
function.
这对于 C++17 程序是正确的。 (C++20 放宽了这一点,因此 try
块现在可以在 constexpr
函数中使用。但是,只有 try
是允许的;不允许执行命中会抛出异常的东西。)
That's why I had to use an immediately invoked lambda expression.
这里的含义是您的方法使您的代码有效。这是不正确的。使用立即调用的 lambda 并不能解决这个问题;它掩盖了问题。 try
仍然是一个问题,但现在编译器不必告诉你它是一个问题。
使用 lambda 将 constexpr
criterion 从直接 “函数体不能包含 try 块” 切换到间接 “至少存在一组参数值,这样函数的调用可以是核心常量表达式的评估子表达式”。 这里棘手的部分是违反后一个标准是“无诊断性” required”,这意味着所有的编译器都是正确的,无论他们是否抱怨这段代码。因此,我将其描述为掩盖问题。
那么为什么...该标准需要重复很长时间...涉及“core constant expressions"? C++17 removed the prohibition against lambdas in core constant expressions, so that much looks good. However, there is still a requirement that all function calls within the constexpr
function also be themselves constexpr
. Lambdas 可以通过两种方式变为 constexpr
的问题是什么。首先,可以明确标记它们constexpr
(但如果你在这里这样做,关于 try
块的抱怨应该回来)。其次,它们可以简单地满足 constexpr
功能要求。但是,你的 lambda 包含一个 try
,所以它不是 constexpr
(在 C++17 中)。
您的 lambda 不是有效的 constexpr
函数。因此在核心常量表达式中不允许调用它。没有通过 can_represent()
的执行路径可以避免调用您的 lambda。因此,can_represent
不是有效的 constexpr
函数,不需要诊断。
取下面的代码:
template <typename T, typename U>
constexpr bool can_represent(U&& w) noexcept
{
return [] (auto&& x) {
try {
return T(std::forward<U>(x)) == std::forward<U>(x);
} catch(...) {
return false;
}
} (std::forward<U>(w));
}
我在常量表达式(模板)中使用这个函数。
gcc
编译没有问题。 clang
和MSVC
没有,感叹函数没有得到常量表达式。
的确,gcc
也没有立即接受;它挂在 try
上,通常在 constexpr
函数中是不允许的。这就是为什么我必须使用立即调用的 lambda 表达式的原因。但是,现在它可以工作了,考虑到它只适用于 gcc
我很困惑。
哪个编译器是正确的?
是否有 lambda 的 属性 允许它在 constexpr
上下文中工作,或者这是某种非标准 gcc
扩展?
[我使用 godbolt 与 clang
和 MSVC
一起编译,因为我的机器上有 gcc 8.1.0
]
[gcc] was getting hung up on the
try
, that normally wouldn't be allowed in aconstexpr
function.
这对于 C++17 程序是正确的。 (C++20 放宽了这一点,因此 try
块现在可以在 constexpr
函数中使用。但是,只有 try
是允许的;不允许执行命中会抛出异常的东西。)
That's why I had to use an immediately invoked lambda expression.
这里的含义是您的方法使您的代码有效。这是不正确的。使用立即调用的 lambda 并不能解决这个问题;它掩盖了问题。 try
仍然是一个问题,但现在编译器不必告诉你它是一个问题。
使用 lambda 将 constexpr
criterion 从直接 “函数体不能包含 try 块” 切换到间接 “至少存在一组参数值,这样函数的调用可以是核心常量表达式的评估子表达式”。 这里棘手的部分是违反后一个标准是“无诊断性” required”,这意味着所有的编译器都是正确的,无论他们是否抱怨这段代码。因此,我将其描述为掩盖问题。
那么为什么...该标准需要重复很长时间...涉及“core constant expressions"? C++17 removed the prohibition against lambdas in core constant expressions, so that much looks good. However, there is still a requirement that all function calls within the constexpr
function also be themselves constexpr
. Lambdas 可以通过两种方式变为 constexpr
的问题是什么。首先,可以明确标记它们constexpr
(但如果你在这里这样做,关于 try
块的抱怨应该回来)。其次,它们可以简单地满足 constexpr
功能要求。但是,你的 lambda 包含一个 try
,所以它不是 constexpr
(在 C++17 中)。
您的 lambda 不是有效的 constexpr
函数。因此在核心常量表达式中不允许调用它。没有通过 can_represent()
的执行路径可以避免调用您的 lambda。因此,can_represent
不是有效的 constexpr
函数,不需要诊断。