代码之家  ›  专栏  ›  技术社区  ›  Lourens Dijkstra

编译器如何区别于常规函数处理lambda?

  •  5
  • Lourens Dijkstra  · 技术社区  · 7 年前

    我想知道编译器是如何对待lambda函数而不是常规函数的。即使排除捕获列表,我认为它的名称,它的行为似乎略有不同。

    例如,正如我在上一篇文章中所用, Trying to pass a constexpr lambda and use it to explicitly specify returning type ,我使用了一个constexpr lambda并将其作为常规函数参数传递。我引用了部分答案。

    constexpr函数的参数本身不是constexpr对象,因此不能在常量表达式中使用它们。

    template <typename Lambda_T>
    constexpr static auto foo(Lambda_T l) {
        return std::array<event, (l())>{};
    } 
    // Compiles with GCC (C++17), though ill-formed (according to the answer of my last post)
    

    然而,吸引我注意的是,这确实 constexpr lambda ,但不通过constexpr正则(全局)函数进行编译。造成这种差异的原因是什么? 在常规函数和lambda函数之间,编译器的行为是否还有其他差异?

    编辑:Lambda实现的示例

    foo([](){ return 4; }); // C++17 Lambda's are implicitly constexpr
    

    编辑:全局函数

    prog.cc:8:20: error: 'l' is not a constant expression
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Passer By    7 年前

    从你的代码片段中删除一些无关的东西,我们得到

    template<typename T>
    constexpr void foo(T t)
    {
        constexpr int i = t();
    }
    
    constexpr int f() { return 42; }
    auto l = []{ return 42; }
    

    评论:

    1. 您正在尝试使用 t() constexpr 在内部 foo . 福 事实上,它可能是一个正常的函数,并且仍然具有相同的行为。

    2. 羔羊 不是吗 函数。它是一个匿名结构,具有 operator() .

      struct L { constexpr int operator()() const { return 42; } };
      

      T 被推导出为与 L 在通话中 foo(l) .

    3. T 推断为 int(*)() 在通话中 foo(f)

    4. 在这两种情况下, t 不是吗 里面的一个constexpr 福 .


    从…起 [expr.const]

    表情 e 是一个核心常量表达式,除非

    • 左值到右值的转换,除非[…]

      • 一个文本类型的非易失性glvalue,它引用一个非易失性对象,其生存期开始于 ;

    通过电话 int(*)() T 对象不是用定义的吗 常量表达式 t() t() 这不是一个 在里面 傅(f) .

    运算符() 不需要左值到右值的转换。由于没有成员访问权限,因此它只是一个 常量表达式 函数调用。因此 t() 是一个 常量表达式 在里面 傅(左)

    有 one more step