Lambda 函数,奇怪的行为
Lambda function, strange behavior
假设我们在全局命名空间中声明了以下 lambda:
auto Less = [](int a,int b) -> bool
{
return a < b;
}
以及以下使用此 lambda 的代码:
template<typename T>
struct foo
{
foo(int v){}
bool operator<(const foo<T>&) const
{
return T(1,2);
}
};
int main()
{
typedef foo<decltype(Less)> be_less;
priority_queue<be_less> data;
}
如您所见,我使用 Less
作为结构 foo
的模板参数。对于 g++4.9.2,此代码无法编译:
test1.cpp:13:21: error: no matching function for call to '<lambda(int, int)>::__lambda0(int, int)'
return T(1,2);
^
test1.cpp:13:21: note: candidates are:
test1.cpp:17:14: note: constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&)
auto Less = [](int a,int b) -> bool
^
test1.cpp:17:14: note: candidate expects 1 argument, 2 provided
test1.cpp:17:14: note: constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&)
test1.cpp:17:14: note: candidate expects 1 argument, 2 provided
但是我可以通过添加两个小更改来解决这个问题,首先我需要将 lambda 更改为:
bool Less = [](int a,int b) -> bool
{
return a < b;
}
如您所见,我只是将 auto
替换为 bool
,仅此修改仍然不起作用:
test1.cpp:13:21: error: expression list treated as compound expression in functional cast [-fpermiss
ive]
return T(1,2);
除非我添加 -fpermissive
,否则我可能会这样更改 operator<
bool
:
bool operator<(const foo<T>&) const
{
return T((1,2));
}
注意双括号。现在代码编译并且一切正常。
我的问题是,auto Less
不起作用但 bool Less
起作用的技术原因是什么?
我相信我知道为什么第二个operator<
中需要双括号,这应该是为了避免编译器将T(1,2)
解释为声明而不是调用。
感谢您的宝贵时间
第一种情况:
在声明中
return T(1,2);
T
是一个类型,lambda表达式的类型。 T(1, 2)
尝试构建该类型的实例,我认为这是不可能的。这解释了编译器错误消息。我不确定您如何才能使用该类型并调用该函数。
在第二种情况下,T
是bool
。
bool(1, 2)
不是有效的表达式。这解释了错误消息。
bool((1, 2))
是 bool(2)
,这是计算结果为 true
.
的有效表达式
在您的第一个示例中,您正在构造 foo<T>
,其中 [T = decltype(Less)]
。所以在这个表达式中
return T(1,2);
您正在尝试通过调用需要 2 int
秒的构造函数来构造 lambda 的实例,这显然不存在。这正是错误消息告诉您的内容
error: no matching function for call to '<lambda(int, int)>::__lambda0(int, int)'
唯一存在的构造函数是 lambda 的复制和移动构造函数(从 lambda 表达式创建的闭包类型不可默认构造),编译器尝试匹配参数并失败
constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&)
constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&)
candidate expects 1 argument, 2 provided
在第二种情况下,通过进行此更改
bool Less = [](int a,int b) -> bool
{
return a < b;
};
您所做的是声明一个名为 Less
的布尔变量并将其初始化为 true
。
这是因为您拥有的 lambda 表达式是无捕获的,这意味着它可以隐式转换为指向函数的指针,该函数采用与 lambda 的 operator()
和 return 相同的参数它与原始 lambda 的类型相同。因此,您将 lambda 表达式转换为 bool(*)(int,int)
.
接下来,函数指针可以隐式转换为 bool
,并且总是计算为 true
(假设它实际上指向一个函数的地址,它在这里就是这样做的)。所以 Less
被初始化为 true
.
现在,decltype(Less)
就是 bool
。所以在这里你尝试将函数样式转换为 bool
,但传入 2 个参数
return T(1,2);
因此出现错误
error: expression list treated as compound expression in functional cast
通过添加额外的括号,您可以得到一个由逗号运算符分隔的 2 个子表达式组成的表达式。这将评估并丢弃第一个子表达式 (1
) 和 return 第二个 (2
) 的值,然后将其转换为 bool
,因此它转换为true
.
我不太确定您要尝试做什么才能提出解决方案,但如果您只想为 foo
定义一些比较谓词,然后将由priority_queue
,那么也许下面的作品?
struct foo
{
foo(int v) {}
};
auto Less = [](foo const& a, foo const& b) -> bool
{
return true; // do whatever comparison you need
};
int main()
{
using my_priority_queue = std::priority_queue<foo, std::vector<foo>, decltype(Less)>;
my_priority_queue data(Less); // pass a copy of the comparator
}
假设我们在全局命名空间中声明了以下 lambda:
auto Less = [](int a,int b) -> bool
{
return a < b;
}
以及以下使用此 lambda 的代码:
template<typename T>
struct foo
{
foo(int v){}
bool operator<(const foo<T>&) const
{
return T(1,2);
}
};
int main()
{
typedef foo<decltype(Less)> be_less;
priority_queue<be_less> data;
}
如您所见,我使用 Less
作为结构 foo
的模板参数。对于 g++4.9.2,此代码无法编译:
test1.cpp:13:21: error: no matching function for call to '<lambda(int, int)>::__lambda0(int, int)'
return T(1,2);
^
test1.cpp:13:21: note: candidates are:
test1.cpp:17:14: note: constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&)
auto Less = [](int a,int b) -> bool
^
test1.cpp:17:14: note: candidate expects 1 argument, 2 provided
test1.cpp:17:14: note: constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&)
test1.cpp:17:14: note: candidate expects 1 argument, 2 provided
但是我可以通过添加两个小更改来解决这个问题,首先我需要将 lambda 更改为:
bool Less = [](int a,int b) -> bool
{
return a < b;
}
如您所见,我只是将 auto
替换为 bool
,仅此修改仍然不起作用:
test1.cpp:13:21: error: expression list treated as compound expression in functional cast [-fpermiss
ive]
return T(1,2);
除非我添加 -fpermissive
,否则我可能会这样更改 operator<
bool
:
bool operator<(const foo<T>&) const
{
return T((1,2));
}
注意双括号。现在代码编译并且一切正常。
我的问题是,auto Less
不起作用但 bool Less
起作用的技术原因是什么?
我相信我知道为什么第二个operator<
中需要双括号,这应该是为了避免编译器将T(1,2)
解释为声明而不是调用。
感谢您的宝贵时间
第一种情况:
在声明中
return T(1,2);
T
是一个类型,lambda表达式的类型。 T(1, 2)
尝试构建该类型的实例,我认为这是不可能的。这解释了编译器错误消息。我不确定您如何才能使用该类型并调用该函数。
在第二种情况下,T
是bool
。
bool(1, 2)
不是有效的表达式。这解释了错误消息。
bool((1, 2))
是 bool(2)
,这是计算结果为 true
.
在您的第一个示例中,您正在构造 foo<T>
,其中 [T = decltype(Less)]
。所以在这个表达式中
return T(1,2);
您正在尝试通过调用需要 2 int
秒的构造函数来构造 lambda 的实例,这显然不存在。这正是错误消息告诉您的内容
error: no matching function for call to '<lambda(int, int)>::__lambda0(int, int)'
唯一存在的构造函数是 lambda 的复制和移动构造函数(从 lambda 表达式创建的闭包类型不可默认构造),编译器尝试匹配参数并失败
constexpr<lambda(int, int)>::<lambda>(const<lambda(int, int)>&)
constexpr<lambda(int, int)>::<lambda>(<lambda(int, int)>&&)
candidate expects 1 argument, 2 provided
在第二种情况下,通过进行此更改
bool Less = [](int a,int b) -> bool
{
return a < b;
};
您所做的是声明一个名为 Less
的布尔变量并将其初始化为 true
。
这是因为您拥有的 lambda 表达式是无捕获的,这意味着它可以隐式转换为指向函数的指针,该函数采用与 lambda 的 operator()
和 return 相同的参数它与原始 lambda 的类型相同。因此,您将 lambda 表达式转换为 bool(*)(int,int)
.
接下来,函数指针可以隐式转换为 bool
,并且总是计算为 true
(假设它实际上指向一个函数的地址,它在这里就是这样做的)。所以 Less
被初始化为 true
.
现在,decltype(Less)
就是 bool
。所以在这里你尝试将函数样式转换为 bool
,但传入 2 个参数
return T(1,2);
因此出现错误
error: expression list treated as compound expression in functional cast
通过添加额外的括号,您可以得到一个由逗号运算符分隔的 2 个子表达式组成的表达式。这将评估并丢弃第一个子表达式 (1
) 和 return 第二个 (2
) 的值,然后将其转换为 bool
,因此它转换为true
.
我不太确定您要尝试做什么才能提出解决方案,但如果您只想为 foo
定义一些比较谓词,然后将由priority_queue
,那么也许下面的作品?
struct foo
{
foo(int v) {}
};
auto Less = [](foo const& a, foo const& b) -> bool
{
return true; // do whatever comparison you need
};
int main()
{
using my_priority_queue = std::priority_queue<foo, std::vector<foo>, decltype(Less)>;
my_priority_queue data(Less); // pass a copy of the comparator
}