如果从lambda表达式生成的类没有默认的ctor,那么如何创建生成的类类型的对象



我正在使用此处列出的资源学习C++。特别是,我在Lippman的C++Primer中读到了lambda表达式。在那里我知道了lambda是函数对象。此外,从lambda表达式生成的类没有默认构造函数。举个例子:

auto wc = find_if(words.begin(), words.end(),
[sz](const string &a){
return s.size() >= sz;
};

上面的lambda表达式将生成一个类,看起来像:

class SizeComp {
SizeComp(size_t n): sz(n) { } // parameter for each captured
variable
// call operator with the same return type, parameters, and body as the lambda
bool operator()(const string &s) const
{ return s.size() >= sz; }
private:
size_t sz; // a data member for each variable captured by value
};

因此,编译器生成的类的一个未命名对象被创建,并作为第三个参数传递给上面显示的std::find_if。我能理解。

现在,我的想法/理解是,由于这个编译器生成的类没有默认的ctor,所以传递给std::find_if的第三个参数不能使用默认的actor创建,因为那样会失败。因此,在内部传递的对象应该使用参数化的ctor创建,比如:

auto wc = find_if(words.begin(), words.end(), SizeComp(sz)); //note the third argument uses the parameterized ctor

我的第一个问题是,因为在C++11中有一个空捕获列表的情况下没有默认的ctor,那么如何创建编译器生成类的对象。我的意思是,在捕获列表为空的情况下,编译器生成的类中不会有数据成员,因此不会有参数化的ctor。这意味着这个编译器生成的类既没有默认的ctor,也没有参数化的ctor。那么如何生成此类的对象。例如,当捕获列表为空时,下面显示的情况将不起作用:

auto wc = find_if(words.begin(), words.end(),
[](const string &a){           //NOTE THE CAPTURE LIST IS EMPTY
return s.size() >= 5;
};

现在,如何创建std::find_if的第三个参数:

auto wc = find_if(words.begin(), words.end(), CompGeneratedClass()); //this can't work because there is no default ctor

我还知道,对于一个普通/普通的用户定义类,如果我们提供了一个用户定义的ctor,那么编译器将不会为该类生成默认的ctor。因此,在我看来,因为在空捕获列表lambda表达式的情况下,没有用户定义的ctor,所以编译器应该为这个编译器生成的类生成一个默认的ctor。但是C++标准规定不会有默认的ctor。所以我的第二个问题是,为什么这个编译器生成的类与用户定义的类有不同的行为。


此外,请注意,此解释不仅限于Lippman的C++Primer。我在CppCon演示中也看到了同样的解释。

这里的问题在于心态。虽然初级读本以人们容易理解的方式解释了这种行为,但它并不是字面意义上的。规范文本描述的是行为,而不是实现行为的方法。编译器实际上不需要像我们一样创建类。

例如,供应商总是可以在构造函数的参数列表中偷偷添加一些秘密标记。想象一下,这就是它所产生的:

struct __secret_tag_at_src_line{};
struct __lambda_at_src_line{
__lambda_at_src_line(__secret_tag_at_src_line, /*Other arguments*/)
// ...
};
// ...
auto wc = find_if(words.begin(), words.end(), __lambda_at_src_line(__secret_tag_at_src_line{}, ...)};

我们无法命名该标记,甚至不知道它的存在,所以我们无法在另一行上创建lambda。并且该类永远不会有默认的构造函数。这是的一种方法。但即使这样,编译器也不必这么做。

执行不受与我们相同的规则约束;只要程序翻译正确,该标准为实现提供了很大的余地。编译器可以只祝福一个字节并说";这是λ;,无需调用构造函数。为什么?因为它实现了标准所说的;可观察的行为是完整的(想想看,C++程序能观察到无捕获lambda的初始化吗?(

有时实现需要";欺骗;;见鬼,众所周知,实现会调用私有构造函数来完成任务。但这并不是真正的欺骗,因为同样的规则并不适用。

最新更新