Lambda函数作为基类
Lambda functions as base classes
玩Lambdas时,我发现了一种有趣的行为,但我并不完全理解。
Supose I有一个从2个模板参数派生的struct Overload
,并且有一个using F1::operator();
子句。
现在,如果我从两个函子派生,我只能访问F1的运算符()(正如我所期望的)
如果我从两个Lambda函数派生,则这不再是真的:我也可以从F2访问运算符()。
#include <iostream>
// I compiled with g++ (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8)
//
// g++ -Wall -std=c++11 -g main.cc
// g++ -Wall -std=c++11 -DFUNCTOR -g main.cc
//
// or clang clang version 3.3 (tags/RELEASE_33/rc2)
//
// clang++ -Wall -std=c++11 -g main.cc
// clang++ -Wall -std=c++11 -DFUNCTOR -g main.cc
//
// on a Linux localhost.localdomain 3.9.6-200.fc18.i686 #1 SMP Thu Jun 13
// 19:29:40 UTC 2013 i686 i686 i386 GNU/Linux box
struct Functor1
{
void operator()() { std::cout << "Functor1::operator()()n"; }
};
struct Functor2
{
void operator()(int) { std::cout << "Functor2::operator()(int)n"; }
};
template <typename F1, typename F2>
struct Overload : public F1, public F2
{
Overload()
: F1()
, F2() {}
Overload(F1 x1, F2 x2)
: F1(x1)
, F2(x2) {}
using F1::operator();
};
template <typename F1, typename F2>
auto get(F1 x1, F2 x2) -> Overload<F1, F2>
{
return Overload<F1, F2>(x1, x2);
}
int main(int argc, char *argv[])
{
auto f = get(Functor1(), Functor2());
f();
#ifdef FUNCTOR
f(2); // this one doesn't work IMHO correctly
#endif
auto f1 = get(
[]() { std::cout << "lambda1::operator()()n"; },
[](int) { std::cout << "lambda2::operator()(int)n"; }
);
f1();
f1(2); // this one works but I don't know why
return 0;
}
标准规定:
lambda表达式的类型(也是闭包对象的类型)是一个唯一的、未命名的非并集类类型
所以每一个Lambda的类型都应该是独一无二的。
我无法解释为什么会这样:有人能解释一下吗?
除了operator()
之外,lambda定义的类(在适当的情况下)还可以提供到函数指针的转换。情况(或者至少是主要情况)是lambda无法捕获任何内容。
如果添加捕获:
auto f1 = get(
[]() { std::cout << "lambda1::operator()()n"; },
[i](int) { std::cout << "lambda2::operator()(int)n"; }
);
f1();
f1(2);
不再提供到pointer to function
的转换,因此尝试编译上面的代码会出现您可能一直预期的错误:
trash9.cpp: In function 'int main(int, char**)':
trash9.cpp:49:9: error: no match for call to '(Overload<main(int, char**)::<lambda()>, main(int, char**)::<lambda(int)> >) (int)'
trash9.cpp:14:8: note: candidate is:
trash9.cpp:45:23: note: main(int, char**)::<lambda()>
trash9.cpp:45:23: note: candidate expects 0 arguments, 1 provided
事实上,您可以从Lambda派生并拥有多态Lambda!
#include <string>
#include <iostream>
int main()
{
auto overload = make_overload(
[](int i) { return '[' + std::to_string(i) + ']'; },
[](std::string s) { return '[' + s + ']'; },
[] { return "[void]"; }
);
std::cout << overload(42) << "n";
std::cout << overload("yay for c++11") << "n";
std::cout << overload() << "n";
}
打印
[42]
[yay for c++11]
[void]
如何?
template <typename... Fs>
Overload<Fs...> make_overload(Fs&&... fs)
{
return { std::forward<Fs>(fs)... };
}
当然。。。这仍然隐藏着魔力。Overload
类"神奇地"从所有Lambda派生,并公开相应的operator()
:
#include <functional>
template <typename... Fs> struct Overload;
template <typename F> struct Overload<F> {
Overload(F&& f) : _f(std::forward<F>(f)) { }
template <typename... Args>
auto operator()(Args&&... args) const
-> decltype(std::declval<F>()(std::forward<Args>(args)...)) {
return _f(std::forward<Args>(args)...);
}
private:
F _f;
};
template <typename F, typename... Fs>
struct Overload<F, Fs...> : Overload<F>, Overload<Fs...>
{
using Overload<F>::operator();
using Overload<Fs...>::operator();
Overload(F&& f, Fs&&... fs) :
Overload<F>(std::forward<F>(f)),
Overload<Fs...>(std::forward<Fs>(fs)...)
{
}
};
template <typename... Fs>
Overload<Fs...> make_overload(Fs&&... fs)
{
return { std::forward<Fs>(fs)... };
}
看到它在Coliru上直播
相关文章:
- 虚拟基类函数中派生类的大小
- 无法访问基类函数 C++
- 如何使派生类函数在调用时始终调用相同的基类函数?
- C++虚拟函数:基类函数是调用的,而不是派生的
- Qt基类函数定义
- 添加字符串类型的类成员会导致调用基类函数而不是子函数
- 有没有办法调用基类函数,该函数在使用私有继承的派生类中被覆盖?
- C++ - 基类函数指针调用的替代方法
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- 重载基类函数是不好的做法吗?
- 在 qml 中公开基类函数
- 调用基类函数时强制使用类名?
- 如何判断哪个派生的类对象称为基类函数
- 获取具有基类函数的派生类
- 有没有办法从基类函数参数中推断出模板参数
- 私有非虚拟基类函数被称为派生类中的函数
- 模板基类函数成员的别名
- 如何用相同的签名从main调用基类函数
- C++ 如何从 main 调用派生的基类函数
- memcpy派生类到基类,为什么还调用基类函数