我可以在模板参数中声明一个 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)确实编译了它。
这是一个编译器错误还是 C++17 允许这样做?
不,这是一个编译器错误。 GCC 7.1 正确拒绝代码。
[expr.prim.lambda]/2:
lambda 表达式是一个 prvalue,其结果对象称为闭包对象。lambda 表达式不得出现在未求值的操作数、模板参数、别名声明、typedef 声明中,或者出现在函数体和默认参数之外的函数或函数模板的声明中。
从我标记为粗体的部分可以看出,lambda 表达式不能出现在模板参数列表中。
这在随后的说明中也明确指出:
[ 注意:目的是防止 lambda 出现在签名中。
如果我猜,我会说这个错误的出现是因为从 C++17 开始,lambda 是隐式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);
}
相关文章:
- 当一个值是非常量但用常量表达式初始化时使用constexpr
- 有没有可能制作一个 constexpr 树?
- 为什么 std::launder 是一个 constexpr 函数?
- 我可以定义一个 constexpr 匿名/未命名变量吗?
- 是否已经有一个 constexpr std::bit_cast 与 g++ 一起使用
- 为什么我不能声明一个 constexpr 本地,而一个 const 一个工作?
- 我可以使用 constexpr 函数声明一个静态数组吗?
- 我可以在模板参数中声明一个 constexpr lambda 吗?
- 用另一个 constexpr 数组对成员数组进行大括号初始化
- 有没有办法构造一个 constexpr 函数来获取双精度的位表示
- 是否可以为 AVR 编写一个 constexpr 舍入函数?
- 如何以静态方式使用另一个 constexpr 数组初始化一个数组
- 为什么在这种情况下它不是一个 constexpr?
- 将对静态存储 cstyle 数组的引用从 constexpr 函数传递到另一个 constexpr 函数
- 如何使用 std::copy 将一个 constexpr 数组复制到另一个 constexpr 数组
- 初始化一个constexpr std ::数组,其大小的n维std ::数组
- 我什么时候可以确定一个 constexpr 全局变量会像 C 宏一样被"forgotten"?
- 将一个 constexpr 数组初始化为其他两个 constexpr 数组的总和
- 一个 constexpr 比 const 更"constant"吗?
- POD结构体的值初始化是一个constexpr