我可以在模板参数中声明一个 constexpr lambda 吗?
Will I be able to declare a constexpr lambda inside a template parameter?
我知道这就像打开了潘多拉魔盒,但它并没有停止困扰我。考虑一个简单的例子:
#include <type_traits>
template <auto>
struct Foo: std::false_type { };
template <>
struct Foo<[](){return 1;}()>:std::true_type { };
int main() {
static_assert(Foo<1>::value);
}
我知道 lambda 不能在未计算的上下文中声明,但显然这里不是这种情况。更奇怪的是 clang 5.0.0(我猜它首先部分支持 constexpr lambda)does compile it.
这是编译器错误还是 C++17 允许这样做?
不,那是一个编译器错误。 gcc 7.1 正确地拒绝了代码。
A lambda-expression is a prvalue whose result object is called the closure object. A lambda-expression shall not appear in an unevaluated operand, in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments.
从我标记为粗体的部分可以看出,lambda 表达式不能出现在模板参数列表中。
这一点在随后的注释中也有明确说明:
[ Note: The intention is to prevent lambdas from appearing in a signature. — end note ]
如果我猜的话,我会说这个错误是因为从 C++17 开始,lambdas 是隐式的 constexpr
,这使得它们可以在编译时表达式中有效调用,比如模板争论。但实际上在模板参数中定义 lambda 仍然是非法的。
请注意,此限制已在 C++20 中解除。 :)
在 C++17 中,您可以将指针作为函数指针类型的模板参数传递给 lambda 函数:
# include <cassert>
template<int(*fn)()>
int get_twice()
{
return fn() * 2;
}
int main()
{
int result = get_twice <+[]() { return 42; }> ();
assert(result == 84);
}
我知道这就像打开了潘多拉魔盒,但它并没有停止困扰我。考虑一个简单的例子:
#include <type_traits>
template <auto>
struct Foo: std::false_type { };
template <>
struct Foo<[](){return 1;}()>:std::true_type { };
int main() {
static_assert(Foo<1>::value);
}
我知道 lambda 不能在未计算的上下文中声明,但显然这里不是这种情况。更奇怪的是 clang 5.0.0(我猜它首先部分支持 constexpr lambda)does compile it.
这是编译器错误还是 C++17 允许这样做?
不,那是一个编译器错误。 gcc 7.1 正确地拒绝了代码。
A lambda-expression is a prvalue whose result object is called the closure object. A lambda-expression shall not appear in an unevaluated operand, in a template-argument, in an alias-declaration, in a typedef declaration, or in the declaration of a function or function template outside its function body and default arguments.
从我标记为粗体的部分可以看出,lambda 表达式不能出现在模板参数列表中。
这一点在随后的注释中也有明确说明:
[ Note: The intention is to prevent lambdas from appearing in a signature. — end note ]
如果我猜的话,我会说这个错误是因为从 C++17 开始,lambdas 是隐式的 constexpr
,这使得它们可以在编译时表达式中有效调用,比如模板争论。但实际上在模板参数中定义 lambda 仍然是非法的。
请注意,此限制已在 C++20 中解除。 :)
在 C++17 中,您可以将指针作为函数指针类型的模板参数传递给 lambda 函数:
# include <cassert>
template<int(*fn)()>
int get_twice()
{
return fn() * 2;
}
int main()
{
int result = get_twice <+[]() { return 42; }> ();
assert(result == 84);
}