从lambda继承是什么意思? [英] What does it mean to inherit from lambda?

查看:127
本文介绍了从lambda继承是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

找到这个有趣的代码:

auto a = [](){};

class B : decltype(a)
{
};

我想知道它的作用。这可以以任何方式有用吗?

I want to know what it does. Can this be useful in any way?

推荐答案

好吧,该代码将编译,但问题是,你将无法默认构造该类 1 的任何对象,因为 的构造函数不可访问。由 lambda 类型保证的唯一构造函数是默认的复制/移动构造函数。并且没有默认构造函数

Well, that code will compile, but the problem is that you will be unable to default construct any object of that class1, because the constructor of the lambda isn't accessible (other than copy/move constructors). The only constructors guaranteed by a lambda type is a defaulted copy/move constructor. And there's no default constructor

[expr。 prim.lambda / 21]


与lambda表达式相关联的闭包类型没有默认的
构造函数,删除的副本分配操作符。它有一个默认的
复制构造函数和一个默认的移动构造函数([class.copy])。 [
注意:这些特殊成员函数隐式定义为通常的
,因此可以定义为已删除。 - end note]

The closure type associated with a lambda-expression has no default constructor and a deleted copy assignment operator. It has a defaulted copy constructor and a defaulted move constructor ([class.copy]). [ Note: These special member functions are implicitly defined as usual, and might therefore be defined as deleted. — end note ]

或从 cppreference

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






无法访问lambda构造函数的历史可追溯到其早期提案,此处

在第3节第2段,我引用:

In section 3, second paragraph, and I quote:


$ c> __ some_unique_name 是一个新名称,未在程序中其他位置使用
,这会导致与
用作闭包类型冲突。这个名称和类的构造函数
不需要暴露给用户 - 用户
在闭包类型中唯一可以依赖的特性是复制构造函数(和move
构造函数,如果该建议被批准)和函数调用
运算符。 Closure类型不需要默认构造函数,赋值
运算符,或者任何其他函数调用之外的访问方式。它可能
是值得实现的,禁止从闭包类型创建派生类
。 ...

In this translation, __some_unique_name is a new name, not used elsewhere in the program in a way that would cause conflicts with its use as a closure type. This name, and the constructor for the class, do not need to be exposed to the user—the only features that the user can rely on in the closure type are a copy constructor (and a move constructor if that proposal is approved) and the function call operator. Closure types do not need default constructors, assignment operators, or any other means of access beyond function calls. It may be worthwhile for implementability to forbid creating derived classes from closure types. ...

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

As you can see, the proposal even suggested that creating derived classes from closure types should be forbidden.

1 当然,您可以使用 a ,以便初始化 B 类型的对象。请参阅

1 of course you can copy-initialize the base class with a in order to initialize an object of type B. See this

现在,针对您的问题:


这有用吗?

Can this be useful in any way?

不是您的确切形式。您的实例只能使用实例 a实例化
然而,如果你继承一个通用的Callable类,如lambda类型,有两种情况我可以想到。

Not in your exact form. Your's will only be instantiable with the instance a. However, if you inherit from a generic Callable Class such as a lambda type, there are two cases I can think of.


  1. 创建一个Functor,按照给定的继承顺序调用一组函子:

一个简单的例子:

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

使用重载运算符()(...)创建一个Functor, c $ c> operator()(...):

Create a Functor with an overloaded operator()(...), overloaded with all base classes' operator()(...):

  • Nir Friedman has already given a good instance of that in his answer to this question.
  • I have also drafted out a similar and simplified example, drawn from His. See it on Coliru
  • Jason Lucas also demonstrated its practical applications in his CppCon 2014 presentation "Polymorphism with Unions". You can find the Repo here, one of exact location in source code here (Thanks Cameron DaCamara)






另一个很酷的技巧:由于 make_functionSequence(...)可调用类。

    //.... 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);

这篇关于从lambda继承是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆