这个 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是用struct
和operator()
实现的,名字不详。因为这里的关键字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类型依赖于p
s类型。所以类型是无限的。
就像@molbdnilo 的评论一样:
It has an infinite type and can't be instantiated.
嗯,我们正在寻找四种类型 P
、Q
、R
、S
例如:
P(Q) -> R
R(P) -> S
Q
和 S
只不过是占位符参数和 return 类型,所以我们不需要它们的任何东西:
struct Q { };
struct S { };
P
和 R
更有趣,因为在他们需要的签名规范中有一个循环: 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 {}; }
最后,C++ 有模板,这让我们有能力用有史以来最无聊的解决方案来解决这个问题:
struct O {
template <class T>
O const &operator()(T) const { return *this; }
};
这样的 O
只会吞下你调用它的任何东西,甚至是它自己的一个实例,甚至都不在乎。
我正在尝试函数式编程,我写了这个。
[=](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是用struct
和operator()
实现的,名字不详。因为这里的关键字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类型依赖于p
s类型。所以类型是无限的。
就像@molbdnilo 的评论一样:
It has an infinite type and can't be instantiated.
嗯,我们正在寻找四种类型 P
、Q
、R
、S
例如:
P(Q) -> R
R(P) -> S
Q
和 S
只不过是占位符参数和 return 类型,所以我们不需要它们的任何东西:
struct Q { };
struct S { };
P
和 R
更有趣,因为在他们需要的签名规范中有一个循环: 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 {}; }
最后,C++ 有模板,这让我们有能力用有史以来最无聊的解决方案来解决这个问题:
struct O {
template <class T>
O const &operator()(T) const { return *this; }
};
这样的 O
只会吞下你调用它的任何东西,甚至是它自己的一个实例,甚至都不在乎。