[英]Constructor parameter access member field of object under construction
我有以下具有成员函数指针的结构。 我的问题是,有没有办法让我传递给它的 lambda 引用它自己的成员变量? IE
struct Foo
{
int aVar{1};
int (*funcPtr)(int);
Foo(int (*func)(int)) : funcPtr(func) {};
};
auto bar1 = Foo([](int a) {std::cout << a;}) // ok
auto bar2 = Foo([](int a) {std::cout << a + bar2.aVar;}) // Not ok but is there a way to access the member variable of the object currently being defined?
我可以达到这种效果吗?
我想在这里实现的是根据您传入的 lambda 自动生成对象的过程。例如:上面的bar2
是一个可以返回任何内容加上其存储值的对象。 即我希望bar2.funcPtr(5) == 5 + bar2.aVar
成为类的不变量。 将来我可能需要另一个可以返回任何减去其存储值的对象,并且我只需要传递相应的 lambda 来执行此操作(如果 lambda 可以访问成员字段),而无需定义新类或方法。
Foo( /* ... */ )
正如在所示代码中使用的,这是一个构造函数调用。 这是在构建一个新对象,就在那里。
在创建新对象并调用其构造函数之前,必须评估构造函数的参数。 这就是 C++ 的工作方式。 没有替代方案或解决方法,最终首先构造对象,然后才评估其构造函数的参数。
出于这个原因,作为参数传递给构造函数的 lambda 在逻辑上是不可能的,“引用它自己的成员变量”。 在这一点上,没有任何东西具有“自己的成员变量”。 对象的构造尚未开始,您不能引用不存在的对象或对象的成员。 在首先评估构造函数的参数之前,无法构造对象。 C++ 不能以这种方式工作。
你需要为你的班级想出一些替代机制。 此时你会发现另一个致命的设计缺陷,它注定了所展示的方法:
int (*funcPtr)(int);
这是一个普通的函数指针。 为了让 lambda 以某种形式或方式引用与其相关的对象,它必须捕获该对象(最有可能是通过引用)。 但是,捕获(按值或引用)的 lambda不能转换为普通函数指针。 只有无捕获的 lambda 表达式才能转换为普通指针。
至少,这必须是std::function
。
现在它是一个std::function
,您可以在 lambda 中通过引用捕获其对象,并将其分配给std::function
。
但这还不是全部,您还必须解决另一个问题:为了使所有这些工作正常进行,对象不再可能以任何方式移动或复制。 这是因为 lambda 捕获了对构造的原始对象的引用,句号。
并且构造对象被复制或移动的事实不会以某种形式或方式修改 lambda,因此它现在神奇地捕获对原始对象的副本或移动实例的引用。
这些都不是不可克服的问题,但它们需要大量的工作来解决,以便得到一个结构良好的 C++ 程序。
lambda 必须有签名int(int)
但你的 lambda 有签名void(int)
所以这是第一个问题。
另一个是 lambda 必须捕获bar2
。 你可以使用std::function
。
#include <iostream>
#include <functional>
struct Foo {
int aVar{1};
std::function<int(int)> funcPtr;
Foo(std::function<int(int)> func) : funcPtr(func) {};
int call(int x) { return funcPtr(x); }
};
int main() {
Foo bar2([&](int a) { return a + bar2.aVar; });
std::cout << bar2.call(2); // prints 3
}
更实用的解决方案是不将 lambda 绑定到最初为其创建的实例,而是让它接受Foo&
作为参数(而不是捕获它)。 使用这种方法移动它不会变得如此麻烦。
例子:
struct Foo {
int aVar;
int(*funcPtr)(Foo&, int); // takes a Foo& as an argument
Foo(int x, int(*func)(Foo&, int)) : aVar(x), funcPtr(func) {};
int call(int x) { return funcPtr(*this, x); }
};
int main() {
Foo bar2(10, [](Foo& f, int a) { return a + f.aVar; });
std::cout << (bar2.call(5) == bar2.aVar + 5) << '\n'; // true
Foo bar3(20, [](Foo& f, int a) { return a * f.aVar; });
std::cout << bar2.call(2) << '\n'; // 10 + 2 = 12
std::cout << bar3.call(2) << '\n'; // 20 * 2 = 40
std::swap(bar2, bar3);
std::cout << bar2.call(2) << '\n'; // swapped, now 40
std::cout << bar3.call(2) << '\n'; // swapped, now 12
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.