在非类型模板参数中计算constexpr lambda
Evaluated constexpr lambda in non-type template argument
Lambda表达式不允许在未求值的上下文中使用(例如在decltype中),并且直到最近才允许使用常量表达式。因此,没有办法在模板参数中使用它们。
在c++ 17中,常量表达式lambda将成为可能。一般来说,这仍然不允许在模板参数中使用它们。
然而,对于非类型模板参数,常量表达式lambda表达式可以在求值的上下文中使用,例如:
template<int N> struct S { constexpr static int value = N; };
int main() {
int N = S<[]()constexpr{return 42;}()>::value;
}
这仍然不起作用,因为无论类型还是非类型,在模板参数中都明确禁止使用lambda表达式。
我的问题是不允许上面的结构背后的原因。我可以理解函数签名中的lambdas类型可能有问题,但这里闭包类型本身无关紧要,只使用(编译时常量)返回值。
我怀疑原因是lambda主体中的所有语句都将成为模板参数表达式的一部分,因此如果在替换期间主体中的任何语句格式错误,则需要应用SFINAE。这可能需要编译器开发人员做大量的工作。
但那实际上是我的动机。如果可以使用上面的结构,那么SFINAE不仅可以用于常量表达式,还可以用于constexpr函数中有效的其他语句(例如文字类型声明)。
除了对编译器编写者的影响外,这是否会引起任何问题,例如标准中的歧义、矛盾或复杂性?
lambda不出现在未求值的上下文中是有意为之的。lambda总是具有唯一类型的事实导致了各种各样的问题。
下面是Daniel Krugler在comp.lang.c++讨论中的几个例子:
确实存在大量允许使用lambda的用例表达式,它可能会极大地扩展可能的特殊情况(包括完整的代码"沙盒")。他们成为的原因排除是由于这种极端扩展的情况下(你)我们为编译器打开了一个潘多拉盒子),事实是它可以导致其他例子中的问题,例如
template<typename T, typename U> void g(T, U, decltype([](T x, T y) { return x + y; }) func);
是无用的,因为每个lambda表达式生成一个唯一的类型,所以就像
g(1, 2, [](int x, int y) { return x + y; });
实际上不起作用,因为参数与
g
调用中lambda的类型不同。最后,它也引起了名字混淆的问题。例如当你有
template<typename T> void f(T, A<sizeof([](T x, T y) { return x + y; })> * = 0);
在一个翻译单元中,但是
另一个翻译单元中的template<typename T> void f(T, A<sizeof([](T x, T y) { return x - y; })> * = 0);
。现在假设您实例化了
f<int>
来自两个翻译单元。这两种功能有不同签名,所以他们必须产生不同的模板实例化。把它们分开的唯一方法就是把body。反过来,这意味着编译器编写者必须中每种语句的名称混淆规则语言。虽然在技术上是可行的,但这被认为是一个规范和实现负担。
这是一大堆问题。尤其是考虑到你写作的动机:
int N = S<[]()constexpr{return 42;}()>::value;
可以很容易地解决,而不是写:
constexpr auto f = []() constexpr { return 42; }
int N = S<f()>::value;
- 如何判断是否在编译时计算了"constexpr"(无需手动检查)
- 编译器如何知道C++constexpr计算不会触发未定义的行为
- 丢弃分支中的嵌套 constexpr-if 语句仍在计算?
- 如何让编译器忽略这个计算结果为 false 的 if-constexpr?
- C++ constexpr:在编译时计算标准数组
- Clang 在编译时不会计算非 constexpr 变量的 constexpr 函数的值
- C++:当与 std::cout 一起使用时,constexpr 函数在编译时不会计算
- 从捕获 constexpr 函数返回值的变量中删除 constexpr 会删除编译时计算
- CONSTEXPR计算的编译时间性能
- 设置具有非constexpr函数的constexpr变量(但可以在编译时间计算)
- 在C++11标准中,它在哪里指定了在翻译过程中何时可以计算constexpr函数
- 扩展编译器以在编译时计算"complicated"函数(具有已知的输入值),超出"constexpr"的范围
- 当在计算constexpr时抛出异常时会发生什么
- constexpr 函数在编译时不计算值
- 为什么 clang 不使用斐波那契的 constexpr 版本计算斐波那契(500)
- 仅在 constexpr 函数主体中的未计算上下文中使用的参数
- 将constexpr(用于在编译时计算常量)替换为模板
- 是基于constexpr的计算图灵完备
- 在编译时计算C字符串的长度.这真的是constexpr吗
- 在非类型模板参数中计算constexpr lambda