在下文中,接受一种初始化成员的方法,另一种方法是错误。我不明白:
template <typename T>
struct LambdaHolder
{
LambdaHolder(T lambdaIn) { lambda = lambdaIn; } // This will not work
LambdaHolder(T lambdaIn) : lambda(lambdaIn) { } // This will work fine
T lambda;
};
int main()
{
auto lambda = []() { return 0; };
LambdaHolder<decltype(lambda) > foo(lambda); // This will work only if the constructor argument is assigned in the initialiser list
// On the other hand
int(*lambdaPtr)() = lambda; // A function pointer
LambdaHolder<decltype(lambdaPtr)> foo(lambdaPtr); // Will work either in initialiser list or constructor body
}
我不理解一些事情。我知道必须在成员初始化列表中初始化某些成员,例如引用和const成员。我不明白为什么它会让我在初始化列表中复制lambda而不是在构造函数体中复制lambda。错误是&#34;您无法构建lambda&#34;。
的副本另外,我能够创建一个指向lambda的指针,并在初始化列表或构造函数体中初始化指针。现在,我知道lambdas和函数指针并不是完全相同的类型,但问题是我认为无捕获的lambda是作为自由函数实现的,这就是为什么你可以设置一个普通的函数指针,并且还认为当作为参数传递时,它肯定会衰减为指针。
基本上我想澄清一下,在构造函数体或初始化列表中初始化之间区别的区别是什么?
编辑:正如Whoan指出的那样,看起来lambda的默认构造函数在C ++ 14之前被删除了,而在C ++ 14之后我就不存在了。
答案 0 :(得分:3)
这是因为lambdas不是Default Constructible:
关闭类型不是DefaultConstructible。关闭类型有&#34;删除(直到C ++ 14)|不(因为C ++ 14)&#34;默认构造函数。
在这个构造函数中:
LambdaHolder(T lambdaIn) { lambda = lambdaIn; } // This will not work
... lambda
需要在分配之前进行默认构建。
答案 1 :(得分:2)
首先,初始化和分配之间存在差异,尽管它们有时看起来很相似。
SomeClass obj1 = val;
是初始化。它会尝试将表达式val
传递给SomeClass
的构造函数,以便创建obj1
。请注意,即使您为operator=
定义了一个或多个SomeClass
,上述代码也不会调用它们。
SomeClass obj2;
obj2 = val;
在此示例中,第一个语句仍需要初始化obj2
以创建可以使用的有效对象,因此需要调用SomeClass
的默认构造函数(由您定义或自动定义)编译器)。然后第二个语句使用obj2
函数(也由您或编译器定义)分配给已初始化的对象operator=
。
每当调用构造函数时,必须在构造函数体启动之前初始化所有基类和成员。正文可能会尝试对成员做任何事情,因此他们需要在那时成为有效的初始化对象。
LambdaHolder(T lambdaIn) : lambda(lambdaIn) { }
对于任何类类型T
,此构造函数使用参数lambda
初始化名为lambdaIn
的成员。由于它们具有相同的类型,这意味着调用复制构造函数。这个是完全有效的。
LambdaHolder(T lambdaIn) { lambda = lambdaIn; }
对于任何类类型T
,由于成员lambda
的mem-initializer缺失但成员必须在正文启动之前初始化,编译器会尝试调用{{1}的默认构造函数创建T
。然后,正文lambda
中的语句尝试调用lambda = lambdaIn;
函数来从参数中分配成员。
是的,lambda的类型是类类型。 lambda本质上是一个快捷方式,用于创建一个类,其中最有用的成员是一个名为operator=
的函数,因此您可以像函数一样调用它。
但lambda类型已删除默认构造函数和已删除的复制赋值运算符。这意味着您永远不会被允许调用它们,因此上述代码在两种不同的方式中无效。
顺便说一句,lambda表达式永远不会自动“衰减”成函数的指针,因为C风格的数组会衰变为指向第一个元素的指针,函数的名称会衰减成指向函数的指针。这种类型的衰减只发生在原始数组和函数类型中。相反,存在从没有捕获列表的lambda类型到函数指针的隐式转换。只有在您实际尝试初始化或从lambda分配特定匹配函数指针类型时才会使用隐式转换。