这个 lambda 的参数是什么类型?

What type is this lambda's parameter?

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

[=](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<LambdaType<int>> 才能接受 q 但是当你把p改成LambdaType<LambdaType<int>>,那么p只接受LambdaType<int>,p不是LambdaType<int>,需要是LambdaType<LambdaType<LambdaType<int>>>才能接受p。

那么,p 是什么类型?

哦对了,这是我在 Whosebug 上的第一个问题

执行级别

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

摘要级别

p(q)(p);
  ↑

假设 p 的类型是 'a->'b

  • 'a是参数的类型
  • 'b 是 return 类型

p(q)(p);
     ↑

我们可以看到return类型('b)可以接收到一个p,其类型是'a->'b,所以我们可以将'b替换为'a->'b。问题解决了吗?没有!

不像factorial这样的复杂递归函数:

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

就像@molbdnilo 的评论一样:

It has an infinite type and can't be instantiated.

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

  • P(Q) -> R
  • R(P) -> S

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

struct Q { };
struct S { };

PR 更有趣,因为在他们需要的签名规范中有一个循环: R 都是调用 [=13= 的结果],并且可以与另一个 P 一起调用。这使得无法使用函数类型或 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