找到了看起来很有趣的这段代码:

auto a = [](){};

class B : decltype(a)
{
};

我想知道它的作用。这有什么用吗?

最佳答案

好的,该代码可以编译,但是问题是您将无法默认构造该class1的任何对象,因为无法访问lambda的构造函数(复制/移动构造函数除外)。 lambda类型保证的唯一构造函数是默认的复制/移动构造函数。而且没有默认的构造函数

[expr.prim.lambda/21]



或来自cppreference:

//ClosureType() = delete;                     //(until C++14)
ClosureType(const ClosureType& ) = default;   //(since C++14)
ClosureType(ClosureType&& ) = default;        //(since C++14)

Lambda构造函数不可访问的历史可以追溯到其早期提议,发现here

在第三部分第二段中,我引用:



如您所见,该建议甚至建议禁止从闭包类型创建派生类。

1当然,您可以使用a复制初始化基类以初始化B类型的对象。参见this

现在,您的问题是:



并非以您的确切形式。您的实例只能使用实例a实例化。
但是,如果您从诸如lambda类型之类的通用Callable类继承,则可以想到两种情况。
  • 创建一个仿函数,该仿函数以给定的继承顺序调用一组仿函数:

    一个简化的例子:
    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...);
    }
    

    用法示例:
    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"
    

    看到它Live on Coliru
  • 创建一个带有重载operator()(...)的Functor,重载所有基类的operator()(...):
  • 尼尔·弗里德曼(Nir Friedman)已经在他的answer中很好地举例说明了这个问题。
  • 我还从His那里起草了一个类似的简化示例。看到它on Coliru
  • 杰森·卢卡斯(Jason Lucas)在他的CppCon 2014 presentation "Polymorphism with Unions"中也演示了其实际应用。您可以在源代码here(感谢Cameron DaCamara)
  • 中找到确切位置之一的Repo here


    另一个很酷的技巧:由于make_functionSequence(...)产生的类型是可调用的类。您可以在以后附加更多lambda或可调用的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);
    

    关于c++ - 从lambda继承意味着什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38024024/

    10-11 22:50
    查看更多