C++ 从lambda继承意味着什么?
找到了以下看起来很有趣的代码:C++ 从lambda继承意味着什么?,c++,C++,找到了以下看起来很有趣的代码: auto a = [](){}; class B : decltype(a) { }; 我想知道它的作用。这在任何方面都有用吗?在下面,加上额外的合成糖a的计算结果类似于此(MyLambda名称是随机名称,就像当您创建名称空间{}时,名称空间名称将是随机的): 因此,当您从lambda继承时,您所做的是从匿名类/结构继承 至于有用性,它和任何其他继承一样有用。您可以在一个对象中具有多个lambda和多个继承的功能,您可以向其添加新方法以扩展它。目前我想不出任何
auto a = [](){};
class B : decltype(a)
{
};
我想知道它的作用。这在任何方面都有用吗?在下面,加上额外的合成糖a
的计算结果类似于此(MyLambda名称是随机名称,就像当您创建名称空间{}
时,名称空间名称将是随机的):
因此,当您从lambda继承时,您所做的是从匿名类/结构继承
至于有用性,它和任何其他继承一样有用。您可以在一个对象中具有多个lambda和多个继承的功能,您可以向其添加新方法以扩展它。目前我想不出任何真正的应用程序,但我肯定有很多
有关更多信息,请参阅。好吧,该代码将被编译,但问题是您将无法默认构造该类别的任何对象,因为lambda的构造函数是不可访问的(复制/移动构造函数除外)。
lambda
类型所保证的唯一构造函数是默认的复制/移动构造函数。并且没有默认的构造函数
与lambda表达式关联的闭包类型没有默认值
构造函数和已删除的副本分配运算符。它有一个默认值
复制构造函数和默认的移动构造函数([class.copy])。[
注意:这些特殊的成员函数通常是隐式定义的,
因此可能被定义为已删除。-结束注释]
或来自:
lambda构造函数不可访问的历史可以追溯到其早期的提案,发现 在第3节第二段中,我引用: 在此翻译中,
\u一些唯一的\u名称
是一个新名称,未使用
在计划的其他地方,可能会与其
用作闭包类型。此名称和类的构造函数,
不需要向用户公开用户所拥有的唯一功能
在闭包类型中可以依赖的是复制构造函数(和移动)
构造函数(如果该建议获得批准)和函数调用
操作人员闭包类型不需要默认构造函数、赋值
运算符或函数调用以外的任何其他访问方式。可能
禁止创建派生类是值得实现的
从闭包类型
如您所见,该提案甚至建议禁止从闭包类型创建派生类
1当然,您可以使用
a
复制并初始化基类,以初始化B
类型的对象。看
现在,请回答您的问题: 这有什么用处吗 不是你的样子。您的仅可通过实例
a
实例化。
但是,如果您从一个通用的可调用类(如lambda类型)继承,我可以想到两种情况
template<typename TFirst, typename... TRemaining>
class FunctionSequence : public TFirst, FunctionSequence<TRemaining...>
{
public:
FunctionSequence(TFirst first, TRemaining... remaining)
: TFirst(first), FunctionSequence<TRemaining...>(remaining...)
{}
template<typename... Args>
decltype(auto) operator () (Args&&... args){
return FunctionSequence<TRemaining...>::operator()
( TFirst::operator()(std::forward<Arg>(args)...) );
}
};
template<typename T>
class FunctionSequence<T> : public T
{
public:
FunctionSequence(T t) : T(t) {}
using T::operator();
};
template<typename... T>
auto make_functionSequence(T... t){
return FunctionSequence<T...>(t...);
}
看到了吗运算符()(…)
创建一个函子,重载的是所有基类的运算符()(…)
:
- Nir Friedman在他对这个问题的回答中已经给出了一个很好的例子李>
- 我还草拟了一个类似的简化例子,摘自他的著作。看到了吗
- Jason Lucas还在他的文章中演示了它的实际应用。您可以在源代码中找到Repo的确切位置(感谢Cameron DaCamara)
另一个很酷的技巧是:
make\u functionSequence(…)
的结果类型是一个可调用的类。您可以附加更多的lambda或稍后调用它
//.... As previously seen
auto trimAndCapitalize = make_functionSequence(trimLeft, trimRight, capitalize);
auto replace = [](std::string& str) -> std::string& { str.replace(0, 4, "Whaaaaat"); return str; };
//Add more Functors/lambdas to the original trimAndCapitalize
auto replaced = make_functionSequence(trimAndCapitalize, replace /*, ... */);
replaced(str2);
这实际上是非常有用的,但这取决于你想对整个事情有多直接。考虑下面的代码:
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <unordered_map>
template <class R, class T, class ... Ts>
struct Inheritor : public T, Inheritor<R, Ts...>
{
using T::operator();
using Inheritor<R, Ts...>::operator();
Inheritor(T t, Ts ... ts) : T(t), Inheritor<R, Ts...>(ts...) {}
};
template <class R, class T>
struct Inheritor<R, T> : public boost::static_visitor<R>, T
{
using T::operator();
Inheritor(T t) : T(t) {}
};
template <class R, class V, class ... T>
auto apply_visitor_inline(V& v, T ... t)
{
Inheritor<R, T...> i(t...);
return boost::apply_visitor(i, v);
}
int main()
{
boost::variant< int, std::string > u("hello world");
boost::variant< int, std::string > u2(5);
auto result = apply_visitor_inline<int64_t>(u, [] (int i) { return i;}, [] (const std::string& s) { return s.size();});
auto result2 = apply_visitor_inline<int64_t>(u2, [] (int i) { return i;}, [] (const std::string& s) { return s.size();});
std::cout << result;
std::cout << result2;
}
#包括
#包括
#包括
#包括
模板
结构继承器:公共T,继承器
{
使用T::operator();
使用Inheritor::operator();
继承者(T,Ts…Ts):T(T),继承者(Ts…){
};
模板
结构继承器:public boost::static\u visitor,T
{
使用T::operator();
继承者(T):T(T){}
};
模板
自动应用\u访客\u内联(V&V、T…T)
{
继承人i(t…);
返回提升::应用访问者(i,v);
}
int main()
{
boost::variantu(“你好世界”);
boost::variantu2(5);
auto result=apply_visitor_inline(u,[](int i){return i;},[](const std::string&s){return s.size();});
auto result2=apply_visitor_inline(u2,[](int i){return i;},[](const std::string&s){return s.size();});
std::难道这看起来很有趣,但它不是在GCC 6.1.0
上编译的吗?您使用的编译器/版本是什么?我见过这种技术用于创建一个重载
函数,该函数接受一组lambda,并将它们包装成一种类型,其中lambda列表中给出的每个参数列表都使用重载函数调用运算符。@克里斯,你能提供一个实施的例子吗?听起来真的很有趣。谢谢。@Cheersandhth.-Alf它很宽泛,不是太宽泛。收票人似乎经常误解that@skypjack,我想我指的是。我不认为这是真的,你可以构造一个B,它只需要有一个接受实例C的构造函数e属于a
,并使用传递的实例构造它的基类。@Nirfiedman。你不能构造B
,除非你用a
复制并只构造实例a
,我的意思是只构造a
…你看,这里的问题是a
已经是唯一类型的实例了…任何其他lambda创建的都不能是a
的类型,我知道,这是我在原始帖子中所写的,如果不清楚的话,很抱歉。无论如何,我认为你是原创的
int main(){
//note: these lambda functions are bug ridden. Its just for simplicity here.
//For correct version, see the one on coliru, read on.
auto trimLeft = [](std::string& str) -> std::string& { str.erase(0, str.find_first_not_of(' ')); return str; };
auto trimRight = [](std::string& str) -> std::string& { str.erase(str.find_last_not_of(' ')+1); return str; };
auto capitalize = [](std::string& str) -> std::string& { for(auto& x : str) x = std::toupper(x); return str; };
auto trimAndCapitalize = make_functionSequence(trimLeft, trimRight, capitalize);
std::string str = " what a Hullabaloo ";
std::cout << "Before TrimAndCapitalize: str = \"" << str << "\"\n";
trimAndCapitalize(str);
std::cout << "After TrimAndCapitalize: str = \"" << str << "\"\n";
return 0;
}
Before TrimAndCapitalize: str = " what a Hullabaloo "
After TrimAndCapitalize: str = "WHAT A HULLABALOO"
//.... As previously seen
auto trimAndCapitalize = make_functionSequence(trimLeft, trimRight, capitalize);
auto replace = [](std::string& str) -> std::string& { str.replace(0, 4, "Whaaaaat"); return str; };
//Add more Functors/lambdas to the original trimAndCapitalize
auto replaced = make_functionSequence(trimAndCapitalize, replace /*, ... */);
replaced(str2);
#include <boost/variant.hpp>
#include <iostream>
#include <string>
#include <unordered_map>
template <class R, class T, class ... Ts>
struct Inheritor : public T, Inheritor<R, Ts...>
{
using T::operator();
using Inheritor<R, Ts...>::operator();
Inheritor(T t, Ts ... ts) : T(t), Inheritor<R, Ts...>(ts...) {}
};
template <class R, class T>
struct Inheritor<R, T> : public boost::static_visitor<R>, T
{
using T::operator();
Inheritor(T t) : T(t) {}
};
template <class R, class V, class ... T>
auto apply_visitor_inline(V& v, T ... t)
{
Inheritor<R, T...> i(t...);
return boost::apply_visitor(i, v);
}
int main()
{
boost::variant< int, std::string > u("hello world");
boost::variant< int, std::string > u2(5);
auto result = apply_visitor_inline<int64_t>(u, [] (int i) { return i;}, [] (const std::string& s) { return s.size();});
auto result2 = apply_visitor_inline<int64_t>(u2, [] (int i) { return i;}, [] (const std::string& s) { return s.size();});
std::cout << result;
std::cout << result2;
}