【问题标题】:What type is this lambda's parameter?这个 lambda 的参数是什么类型的?
【发布时间】:2017-12-16 05:54:50
【问题描述】:

我正在尝试函数式编程,我写了这个。

[=](auto p) { 
    return [=](auto q) { 
        return p(q)(p); 
    }; 
})

我开始想知道这怎么可能,p 的类型是什么?

所以,我写了这样的东西。

template<class Type>
using LambdaType = std::function<std::function<Type(Type)>(Type)>;

[=](LambdaType<int> p) {
    return [=](LambdaType<int> q) {
        return p(q)(p);
    };
}

编译时,编译器会报错。

error C2664: 'std::function<Type (int)> std::_Func_class<_Ret,int>::operator ()(int) const': cannot convert argument 1 from 'std::function<std::function<Type (int)> (int)>' to 'int'
error C2664: 'main::<lambda_cec7eb77d9cd29f3c40710200090f154>::()::<lambda_b8db28542cb51159223ad8d89c63d794>::()::<lambda_224126017af42fcee190e88f299089fc>::()::<lambda_415db9fd88f1008b25af42ccb33b1c77> main::<lambda_cec7eb77d9cd29f3c40710200090f154>::()::<lambda_b8db28542cb51159223ad8d89c63d794>::()::<lambda_224126017af42fcee190e88f299089fc>::operator ()(std::function<std::function<Type (std::function<std::function<int (int)> (int)>)> (std::function<std::function<int (int)> (int)>)>) const': cannot convert argument 1 from 'main::<lambda_cec7eb77d9cd29f3c40710200090f154>::()::<lambda_b8db28542cb51159223ad8d89c63d794>::()::<lambda_fa72c454c823301ba6dfa9cba6f558e0>' to 'std::function<std::function<Type (std::function<std::function<int (int)> (int)>)> (std::function<std::function<int (int)> (int)>)>'

但那时我意识到 p 只接受整数,但 p 需要是 LambdaType&lt;LambdaType&lt;int&gt;&gt; 才能接受 q 但是当你把p改成LambdaType&lt;LambdaType&lt;int&gt;&gt;时,p只接收LambdaType&lt;int&gt;,但p不是LambdaType&lt;int&gt;,它需要是LambdaType&lt;LambdaType&lt;LambdaType&lt;int&gt;&gt;&gt;才能接收p。

那么,p是什么类型?

顺便说一句,这是我关于stackoverflow的第一个问题

【问题讨论】:

  • 在 lambda 用于评估它的上下文之前,'p' 的类型是未知的。这实际上只是编写模板函数的另一种方式。 template &lt;typename type_of_p&gt; auto lambda(type_of_p p)... 什么是 type_of_p -- 直到你真正使用它才知道。
  • 如果你真的调用了那个 lambda,你会更容易看到发生了什么。
  • 类型是在编译时推导出来的,取决于你使用的类型。
  • 您的困惑似乎是因为 lambda 不是 std::function&lt;SOME_SIGNATURE&gt; 类型的事实引起的

标签: c++ lambda auto


【解决方案1】:

嗯,我们正在寻找四种类型PQRS,例如:

  • P(Q) -&gt; R
  • R(P) -&gt; S

QS 只不过是占位符参数和返回类型,所以我们不需要它们的任何东西:

struct Q { };
struct S { };

PR 更有趣,因为它们需要的签名规范中有一个循环:R 既是调用P 的结果,又可以被另一个@ 调用987654336@。这使得无法使用函数类型或 lambda 类型进行声明,它们仅由其(此处为无限递归)签名定义。

但是 C++ 可以使用仿函数轻松地对其进行排序——只需给它一个名称,并且借助简单的前向声明,您就可以很好地创建循环仿函数:

struct P;

struct R {
    S operator()(P) const;
};

struct P {
    R operator()(Q) const { return {}; }
};

inline S R::operator()(P) const { return {}; }

Live demo on Coliru


最后,C++ 有模板,这让我们有能力用有史以来最无聊的解决方案来解决这个问题:

struct O {
    template <class T>
    O const &operator()(T) const { return *this; }
};

这样的O 只会吞下你用它来称呼它的任何东西,甚至是它自己的一个实例,甚至都不在乎。

Live demo on Coliru

【讨论】:

    【解决方案2】:

    实施级别

    c++ 中,Lambda 使用structoperator() 实现,其名称未知。因为这里的关键字auto表示类型是泛型的,所以template是必须的。您必须通过为结构模板提供参数来显式实例化结构,然后才能确定'a'b 代表什么。

    抽象层次

    p(q)(p);
      ↑
    

    假设p的类型是'a-&gt;'b

    • 'a是参数的类型
    • 'b 是返回类型

    p(q)(p);
         ↑
    

    我们可以看到返回类型('b)可以接收到一个p,其类型是'a-&gt;'b,所以我们可以将'b替换为'a-&gt;'b。问题解决了吗?不!

    不像factorial这样的琐碎递归函数:

    std::function<int(int)> factorial = [&](int a) {return a == 1 ? 1 : a*factorial(a-1);};
    
    • 对于Factorial:它的返回类型仍然不依赖于类型(Factorial) 本身。
    • 对于p:它的返回类型依赖于ps 类型。所以类型是无限的。

    就像@molbdnilo 的评论:

    它有一个无限类型,不能被实例化。

    【讨论】:

    • 如果pa -&gt; a -&gt; b,那么p(q) 就是a -&gt; b,但对于某些c,它必须是a -&gt; a -&gt; b -&gt; c
    • @molbdnilo 'b' 的类型也可以是 'b->c'。
    • 糟糕,我的意思是(a -&gt; a -&gt; b) -&gt; c
    • @molbdnilo 是的,你是对的。最好说我们永远无法推断出'a 的类型,因为没有必要引入第三种类型cd。我稍后会更新我的答案:)
    • 问题是类型是无限的。如果p 的类型为Pp(q) 的类型为P -&gt; c,对于一些c,所以P 必须是a -&gt; P -&gt; c,对于一些ac。这是不可能的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多