【问题标题】:C++ type of lambda closure returned from functions从函数返回的 C++ 类型的 lambda 闭包
【发布时间】:2016-02-09 11:57:55
【问题描述】:

考虑以下示例代码:

int main()
{
    auto id = []()
    {
        auto ret = [](auto u) { return u; };
        return ret;
    };

    //same closure type -- prints '1'
    auto f1 = id();
    auto g1 = id();
    std::cout<<std::is_same<decltype(f1), decltype(g1)>::value<<std::endl;

    //differenct closure type -- prints '0'
    auto f2 = [](auto u) { return u; };
    auto g2 = [](auto u) { return u; };    
    std::cout<<std::is_same<decltype(f2), decltype(g2)>::value<<std::endl;
}

DEMO

问题:

  • 为什么第一次调用std:is_same时返回的闭包对象的类型相同? (使用“普通”函数模板,以及在main() 的主体中定义add 时,也会获得相同的结果。)
  • 与第二次调用有何不同——正如我对 this answer 所期望的那样——闭包类型不同?

【问题讨论】:

  • 好吧,你调用的是 addoperator() 的同一个专业化......
  • 什么是 t "auto f2 = [t{​​3}](auto u) { return t + u; };"
  • @Columbo:我期待以下结果:当调用addoperator() 时,在主体中生成并返回具有唯一类型的新的唯一闭包——因为它也发生在主要的。这种期望有什么问题?
  • 如果在循环中调用 lambda add 并在运行时提供循环边界会发生什么?编译器如何能够为循环的每次迭代生成唯一的 lambda 类型?我在这里注意到add 使用的类型在所有情况下都是int 根据示例(请参阅初始帖子)
  • @Niall:我得到了例子,谢谢。你是对的,这很自然:具有给定参数的成员函数具有唯一的返回类型,而不是每次调用的新类型。

标签: c++ lambda closures c++14


【解决方案1】:

我已经扩展了您的(未经编辑的)示例以获得更多信息:

#include<iostream>
#include<type_traits>
#include<utility>
#include<functional>
#include<array>
#include<tuple>
#include<algorithm>
#include<string>


    auto add = [](auto t)
    {
        auto ret = [t](auto u) { return t + u; };
        return ret;
    };

    int main()
    {    
        //same closure type -- prints '1'
        auto f1 = add(3);
        auto g1 = add(4);
        auto h1 = add(1.);
        std::cout<<std::is_same<decltype(f1), decltype(g1)>::value<<std::endl;
        std::cout<<std::is_same<decltype(f1), decltype(h1)>::value<<std::endl;
        std::cout<<typeid(f1).name() <<"\t" << typeid(g1).name()<<"\t" << typeid(h1).name()<<std::endl;

        //differenct closure type -- prints '0'
        auto f2 = [t{3}](auto u) { return t + u; };
        auto g2 = [t{4}](auto u) { return t + u; };    
        std::cout<<std::is_same<decltype(f2), decltype(g2)>::value<<std::endl;
        std::cout<<typeid(f2).name() << "\t" << typeid(g2).name()<<std::endl;

        //using same line multiple times
        std::vector<std::string> types;
        for(int i=0; i<3; ++i)
            types.push_back(typeid([t{i}](auto u) { return t + u;     }).name());

        for(auto type:types)
            std::cout<<type<<std::endl;
    }

DEMO

示例输出(来自演示,使用 g++):

1
0
ZNKUlT_E_clIiEEDaS_EUlS_E_  ZNKUlT_E_clIiEEDaS_EUlS_E_  ZNKUlT_E_clIdEEDaS_EUlS_E_
0
Z4mainEUlT_E_   Z4mainEUlT_E0_
Z4mainEUlT_E1_
Z4mainEUlT_E1_
Z4mainEUlT_E1_

对我来说,这看起来像这样:
如您链接的答案中所述,每个 lambda 都有自己的类型。
然而,add()-function 被视为模板,因此每种类型都有一个专门化(在我的示例中为 int 和 float)。由于您只需调用此函数两次(对于 int 部分),相同的代码将被执行两次 - 在像 c++ 这样的强类型语言中,这当然会生成两次相同的类型。如果在循环中调用,也会发生同样的情况。
然而,如果声明了一个 lambda,它看起来是一样的,编译器有两个(可能)不同的表达式来编译 - 并创建不同的类型。在此处的示例输出中,例如类型名中包含“main”,可能是对声明 lambda 的范围的一些引用。

【讨论】:

    猜你喜欢
    • 2014-02-23
    • 1970-01-01
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 2018-12-15
    • 2019-09-06
    相关资源
    最近更新 更多