C++11 quot;overloaded lambdaquot; with variadic template and variable capture(C++11“重载的lambda带有可变参数模板和变量捕获)
问题描述
我正在研究一个 C++11 习语,它可能被称为重载 lambda":
I'm investigating a C++11 idiom which might be called "overloaded lambda":
- http://cpptruths.blogspot.com/2014/05/fun-with-lambdas-c14-style-part-2.html
- http://martinecker.com/martincodes/lambda-expression-overloading/
使用可变参数模板重载 n 函数对我来说似乎很有吸引力,但事实证明它不适用于变量捕获:any of [&]
(使用我本地的 GCC 4.9.1 和 ideone.com GCC 5.1)[=]
[y]
[&y]
(和 [this]
等,如果在成员函数中)导致编译失败:<代码>错误:没有匹配的调用 '(overload<main(int, char**)::<lambda(int)>, main(int, char**)::<lambda(char*)>>) (char*&)'
Overloading n functions with variadic template seemed very appealing to me but it turned out it didn't work with variable capture: any of [&]
[=]
[y]
[&y]
(and [this]
etc if in a member function) lead to compilation failure: error: no match for call to '(overload<main(int, char**)::<lambda(int)>, main(int, char**)::<lambda(char*)> >) (char*&)'
(with my local GCC 4.9.1 and ideone.com GCC 5.1)
另一方面,固定的二元情况没有遇到这个问题.(尝试将 ideone.com 上的第一个 #if 0
更改为 #if 1
)
On the other hand, the fixed 2-ary case didn't suffer that problem. (Try changing the first #if 0
to #if 1
on ideone.com)
对这里发生的事情有什么想法吗?这是编译器错误,还是我偏离了 C++11/14 规范?
Any ideas on what's happening here? Is this a compiler bug, or am I deviating from the C++11/14 spec?
http://ideone.com/dnPqBF
#include <iostream>
using namespace std;
#if 0
template <class F1, class F2>
struct overload : F1, F2 {
overload(F1 f1, F2 f2) : F1(f1), F2(f2) { }
using F1::operator();
using F2::operator();
};
template <class F1, class F2>
auto make_overload(F1 f1, F2 f2) {
return overload<F1, F2>(f1, f2);
}
#else
template <class... Fs>
struct overload;
template <class F0, class... Frest>
struct overload<F0, Frest...> : F0, overload<Frest...> {
overload(F0 f0, Frest... rest) : F0(f0), overload<Frest...>(rest...) {}
using F0::operator();
};
template <>
struct overload<> {
overload() {}
};
template <class... Fs>
auto make_overload(Fs... fs) {
return overload<Fs...>(fs...);
}
#endif
#if 0
#define CAP
#define PRINTY()
#else
#define CAP y
#define PRINTY() cout << "int y==" << y << endl
#endif
int main(int argc, char *argv[]) {
int y = 123;
auto f = make_overload(
[CAP] (int x) { cout << "int x==" << x << endl; PRINTY(); },
[CAP] (char *cp) { cout << "char *cp==" << cp << endl; PRINTY(); });
f(argc);
f(argv[0]);
}
推荐答案
重载解析仅适用于存在于公共范围内的函数.这意味着第二个实现无法找到第二个重载,因为您没有将函数调用运算符从 overload
导入 overload
.
Overload resolution works only for functions that exist in a common scope. This means that the second implementation fails to find the second overload because you don't import function call operators from overload<Frest...>
into overload<F0, Frest...>
.
但是,非捕获 lambda 类型将转换运算符定义为与 lambda 的函数调用运算符具有相同签名的函数指针.这个转换操作符可以通过名称查找找到,这就是当你删除捕获部分时调用的内容.
However, a non-capturing lambda type defines a conversion operator to a function pointer with the same signature as the lambda's function call operator. This conversion operator can be found by name lookup, and this is what gets invoked when you remove the capturing part.
适用于捕获和非捕获 lambda 并且始终调用 operator()
而不是转换运算符的正确实现应如下所示:
The correct implementation, that works for both capturing and non-capturing lambdas, and that always calls operator()
instead of a conversion operator, should look as follows:
template <class... Fs>
struct overload;
template <class F0, class... Frest>
struct overload<F0, Frest...> : F0, overload<Frest...>
{
overload(F0 f0, Frest... rest) : F0(f0), overload<Frest...>(rest...) {}
using F0::operator();
using overload<Frest...>::operator();
};
template <class F0>
struct overload<F0> : F0
{
overload(F0 f0) : F0(f0) {}
using F0::operator();
};
template <class... Fs>
auto make_overload(Fs... fs)
{
return overload<Fs...>(fs...);
}
演示
在c++17,有了类模板参数推导和using
声明的包扩展,上面的实现可以简化为:
In c++17, with class template argument deduction and pack expansion of using
declarations in place, the above implementation can be simplified to:
template <typename... Ts>
struct overload : Ts... { using Ts::operator()...; };
template <typename... Ts>
overload(Ts...) -> overload<Ts...>;
演示 2
这篇关于C++11“重载的lambda"带有可变参数模板和变量捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:C++11“重载的lambda"带有可变参数模板和变量捕获
基础教程推荐
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 从 std::cin 读取密码 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 使用从字符串中提取的参数调用函数 2022-01-01