gpt4 book ai didi

c++ - 将 lambda 存储为成员混淆

转载 作者:太空狗 更新时间:2023-10-29 20:58:24 28 4
gpt4 key购买 nike

我正在阅读 Scott Meyer 的 Effective Modern C++ 并点击了他建议使用 lambda 代替 std::function 的项目> 和 std::bind。我理解他的论点和他关于 std::function 缺点的主张,我同意他的看法。

从今天开始,我决定改用模板来存储 lambda(不需要修改器)。我知道每个 lambda 的类型只有编译器知道,甚至两个相同的 lambda 也会有不同的类型,那么下面的代码如何编译并正常工作?

template<typename LambdaT>
class CaptureLambda
{
public:
CaptureLambda(const LambdaT& fn)
: mActionFn(fn) // initialize mActionFn to a user supplied lambda
{}

private:
LambdaT mActionFn{ []{} }; // initialize mActionFn to an empty lambda
};

我感到困惑的一点是,为什么 mActionFn 默认初始化为空 lambda,在成员声明中具有不同的类型,但该类的构造函数很乐意接受另一种类型的 lambda 在其参数中?他们能cast吗?如果是,为什么下面的内容会让编译器不高兴?

// Class stuff...

template<typename T>
void resetActionFn(const T& newFn) { // setter member
mActionFn = newFn;
}

// Class stuff...

最佳答案

非静态数据成员初始化器只有在构造函数没有指定不同的初始化器时才会被使用。

给定

struct S {
int i = 3;
S() : i(4) { }
};

你没有得到一个默认的构造函数,它首先将 i 初始化为 3,然后将它重新初始化为 4,你只是获取将 i 初始化为 4 的构造函数。

你的类(class)也一样。您没有任何不会初始化mActionFn 的构造函数,因此永远不会使用初始化程序。

现在,正如 Piotr S. 在评论中指出的那样,一般来说,初始化器必须在语义上仍然有效,但是您的数据成员具有依赖类型,因此无法在模板定义时检查有效性,并且初始化器永远不会由于未使用而被实例化,因此在实例化时也未检测到错误。一个类似的更简单的例子是

template <typename T>
struct S {
T x = 3;
S() : x(0) { }
};
int main() {
S<void*>();
}

即使 3 是类型为 void* 的字段的无效初始化程序,GCC 也会默默地接受它。 clang 拒绝了它。该标准不清楚模板的实例化是否会导致任何未使用的 NSDMI 的实例化,一些编译器仅在需要时才实例化它们。 There is agreement that they should be instantiated only as needed, but there are some problems with that approach, which is why not all compilers implement that yet.

关于c++ - 将 lambda 存储为成员混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27695646/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com