Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从lambda继承意味着什么?_C++ - Fatal编程技术网

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;
    }