代码之家  ›  专栏  ›  技术社区  ›  user4407569

在非类型模板参数中计算了constexpr lambda

  •  5
  • user4407569  · 技术社区  · 9 年前

    Lambda表达式不允许在未赋值的上下文中使用(例如在decltype中),直到最近才可以是常量表达式。因此,无法在模板参数中使用它们。

    然而,在C++17中,常数表达式lambdas是可能的。一般来说,这仍然不允许在模板参数中使用它们。

    但是,对于非类型模板参数,常量表达式lambda表达式可以在计算的上下文中使用,例如:

    template<int N> struct S { constexpr static int value = N; };
    
    int main() {
        int N = S<[]()constexpr{return 42;}()>::value;
    }
    

    但这仍然不起作用,因为无论是类型还是非类型,模板参数中都明确禁止lambda表达式。

    我的问题是不允许上述构造的原因。我可以理解,函数签名中的lambdas类型可能有问题,但这里闭包类型本身是不相关的,只使用了(编译时常量)返回值。

    但这实际上是我的动机。如果可以使用上面的构造,那么SFINAE不仅可以用于常量表达式,还可以用于constexpr函数中的其他有效语句(例如文字类型声明)。

    除了对编译器编写者的影响外,这是否会导致任何问题,例如标准中的歧义、矛盾或复杂性?

    1 回复  |  直到 9 年前
        1
  •  2
  •   Barry    9 年前

    lambdas不会出现在未经评估的上下文中,这是非常有意的。lambdas总是有独特的类型,这导致了各种各样的问题。

    以下是来自 comp.lang.c++ discussion 丹尼尔·克鲁格勒(Daniel Krugler):

    确实存在大量允许lambda的用例 表达式,它可能会极大地扩展可能的sfinae情况 (包括完整的代码“沙盒”)。他们成为 被排除在外正是因为sfinae案件的这种极端延伸(您 在你的其他例子中引发问题,例如。

    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 .

    最后,它也造成了名称混乱的问题。E、 g.当你有

    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> 来自两个翻译单元。这两种功能不同 签名,因此它们必须生成不同的损坏模板 实例化。将它们分开的唯一方法是将 身体 为 语言虽然技术上可行,但这被认为是 规范和实现负担。

    int N = S<[]()constexpr{return 42;}()>::value;
    

    可以通过编写以下内容轻松解决:

    constexpr auto f = []() constexpr { return 42; }
    int N = S<f()>::value;