我最近刚刚对函数式反应式编程及其是什么进行了一些试验,当我试图在 c++ 中实现类似的东西时,我求助于 lambda。我想出了这样的开始,
template<class T>
class Reactive
{
public:
Reactive(T data)
{
m_Data = data;
}
Reactive(std::function<T()> func, T data)
{
m_Data = data;
m_Affecter = func;
}
template<class H>
Reactive & operator+(const H & rhs)
{
m_Data += rhs;
return *this;
}
template<class H>
Reactive operator+(Reactive<H> & rhs)
{
std::function<decltype(m_Data + rhs.m_Data)()> func;
if (!rhs.m_Affecter)
func = [&](){return m_Data + rhs.m_Data;};
else
func = [&](){return m_Data + rhs.m_Affecter();};
return Reactive<decltype(m_Data + rhs.m_Data)> (func, m_Data + rhs.m_Data);
}
Reactive & operator=(const T & data)
{
m_Data = data;
return *this;
}
Reactive & operator=(const Reactive & rhs)
{
m_Data = rhs.m_Data;
m_Affecter = rhs.m_Affecter;
return *this;
}
T & Get()
{
return m_Data;
}
void Update()
{
m_Data = m_Affecter();
}
private:
std::function<T()> m_Affecter;
T m_Data;
};
到目前为止它只支持添加。我试图创建一个称为响应式的对象,它可以环绕任何其他类型,除了在对其执行数学运算时,会创建一个 lambda,在该操作发生的位置,以便记住已经完成的操作之前,并在其中一个影响值发生更改时再次执行此操作(在调用更新函数之后)。例如,如果我要这样做。
Reactive<int> cheh = 0;
Reactive<int> meh = 3;
Reactive<int> peh = 7;
cheh = meh + peh;
meh = meh + 4;
cheh.Update();
std::cout << cheh.Get();
那么继承人会发生什么。将第五行中的两个 Reactive 相加将使另一个 Reactive 将它们的两个值添加到 10,并将其影响器设置为执行类似操作的 lambda, &{meh.m_Data + peh.m_Data} 。然后那个 Reactive 将被分配给 cheh。当值 m_meh 添加了 4 并更新了 cheh 时,它的影响器被调用为新值 14,这就是打印到屏幕上的内容,完全符合我的预期。
但后来我开始思考,如果参与 cheh 影响者的那些反应物之一超出范围怎么办。如果处理不当,程序应该会出错。所以我这样做了,
Reactive<int> cheh = 0;
Reactive<int> meh = 3;
{
Reactive<int> peh = 7;
cheh = meh + peh;
peh = peh + 4;
}
cheh.Update();
std::cout << cheh.Get();
在调用 update 时,在他的影响器中发生的反应性 peh 已经超出范围并且不再存在。然而,这个程序和 cheh 的影响器成功执行,它像以前一样打印出 14。我知道 lambda 中的值是由引用捕获传入的,那么影响函数如何仍然访问对 peh 的引用?只要 lambda 存在,通过引用传递给 lambda 的对象或整数类型是否会强制它们持续存在?有什么腥味...