私は、依存値が変更されたときに値を変更する機能的リアクティブプログラミングを利用する通常のデータ値を表すオブジェクトに取り組んでいます。つまり、var3 = var1 + var2; があるとしましょう。var1 の値を変更すると、var3 の値が自動的に更新されます。C++ ではこれは大変ですが、更新関数が別のワーカー スレッドのどこかで呼び出されているため、機能的に反応しているように見せることができます。
そこで、私の方法を以下に示しました。任意の型を持つことができる Reactive と呼ばれるテンプレート オブジェクトを作成し、演算子をオーバーロードして、これらのリアクティブのうちの 2 つを加算すると、結果の値がそれらの合計に等しいだけでなく、ラムダがこれは操作を std::function に格納します。これは、更新関数を呼び出したときにいつでも結果の値を更新するために後で再度呼び出すことができます。
いくつかの問題が発生します。依存する値の 1 つが破棄された場合はどうなりますか。結果として得られる Reactive には、有効なラムダであると見なされるものがまだありますが、ラムダが使用した引数は存在しなくなります。これを説明するために、boost::signals2 を使用してシグナルとスロットのシステムをセットアップし、依存関係のいずれかが破壊されたことを結果に通知します。結果がシグナルを受信すると、そのアフェクター関数は無効になり、更新時に呼び出されません。
リアクティブがその + 操作を実行できるようにするには、一時的なリアクティブを作成する必要があります。これには独自のシグナルがあり、次に = 演算子をオーバーロードして、一時的なデータを結果のリアクティブに移動する必要があります。ただし、シグナルはコピーできません。私は std::unique_ptr に destruct シグナルを含めることでこれを回避し、オペレーター = Reactive && を受け取ったときに std::move を使用しました。危機は回避されました。
ここで私は立ち往生しています。後で気がついたのですが、move の構築は問題なく実行できましたが、Reactive の 1 つをコピーして構築する方法がまだないことに気付きました。そして、次のようにします: var4 = var3; 次に、どうにかして var1 と var2 の破壊シグナルは、それらが破壊されたことを var4 に通知する方法を必要とします。私が最終的に思いついたのは、boost::signals2::signal を含むファンクタである Proxy というサブオブジェクトを設定し、各オブジェクトが std::shared_ptr に含まれるようにすることでした。 . Reactive がそのプロキシへの参照を持っている場合、inform destruct メソッドをそのプロキシに接続します。次に、依存関係がそのプロキシに信号を添付します。プロキシが呼び出されると、すべての接続も呼び出されます。
問題は、プロキシを依存信号に接続するには、プロキシにコピーコンストラクターが必要であるか、少なくとも msvc が私に与えているエラーです。どうやら boost::signals2::signal::connect はそのコピー コンストラクターを使用しますが、プロキシ自体にシグナルが含まれているため使用できません。これが最善の解決策かどうかまだわからないので、このすべての情報を提供します。私はシグナルとスロットに最も精通しているため、シグナルとスロットを選択しましたが、より良い解決策があれば指摘してください。それ以外の場合は、このエラーを回避してください。
ところで、Slot は、Unreact() 関数を各 Reactive に固有のファンクターにする方法にすぎません。
オブジェクトは次のとおりです。
template<class T>
class Reactive
{
template<class H>
friend class Reactive;
class Slot : public boost::signals2::trackable
{
public:
Slot(std::function<void()> & func) :
m_Func(func)
{}
void operator()()
{m_Func();}
private:
std::function<void()> m_Func;
};
class Proxy : public boost::signals2::trackable
{
Proxy(const Proxy & s);
Proxy & operator=(const Proxy & s);
public:
Proxy(){}
void operator()()
{m_Informer();}
void attach(Slot & m_Unreacter)
{m_Informer.connect(m_Unreacter);}
private:
boost::signals2::signal<void()> m_Informer;
};
public:
~Reactive()
{
(*m_SendDestruct)();
}
Reactive() :
m_SendDestruct(new boost::signals2::signal<void()>),
m_Proxy(new Proxy),
m_ReceiveDestruct(std::function<void()>(std::bind(&Reactive::Unreact, this))),
m_Affecter(nullptr)
{
m_Proxy->attach(m_ReceiveDestruct);
}
template<class H>
Reactive(const H & data) :
m_SendDestruct(new boost::signals2::signal<void()>),
m_Proxy(new Proxy),
m_ReceiveDestruct(std::function<void()>(std::bind(&Reactive::Unreact, this))),
m_Affecter(nullptr),
m_Data(data)
{
m_Proxy->attach(m_ReceiveDestruct);
}
Reactive(const Reactive & reac) :
m_SendDestruct(new boost::signals2::signal<void()>),
m_Proxy(reac.m_Proxy),
m_ReceiveDestruct(std::function<void()>(std::bind(&Reactive::Unreact, this))),
m_Affecter(reac.m_Affecter),
m_Data(reac.m_Data)
{
m_Proxy->attach(m_ReceiveDestruct);
}
Reactive(Reactive && reac) :
m_SendDestruct(std::move(reac.m_SendDestruct)),
m_Proxy(reac.m_Proxy),
m_ReceiveDestruct(std::function<void()>(std::bind(&Reactive::Unreact, this))),
m_Affecter(reac.m_Affecter),
m_Data(reac.m_Data)
{
m_Proxy->attach(m_ReceiveDestruct);
}
Reactive & operator=(const T & data)
{
m_Data = data;
return *this;
}
Reactive & operator=(const Reactive & reac)
{
m_Proxy = reac.m_Proxy;
m_Proxy.attach(m_ReceiveDestruct);
m_Affecter = reac.m_Affecter;
m_Data = reac.m_Data;
}
Reactive & operator=(Reactive && reac)
{
m_SendDestruct = std::move(reac.m_SendDestruct);
m_Proxy = reac.m_Proxy;
m_Affecter(reac.m_Affecter);
m_Data(reac.m_Data);
}
template<class H>
Reactive & operator+(const H & rhs)
{
m_Data += rhs;
return *this;
}
template<class H>
auto operator+(Reactive<H> & rhs) -> Reactive<decltype(m_Data + rhs.m_Data)> &&
{
Reactive<decltype(m_Data + rhs.m_Data)> m_temp;
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();};
m_SendDestruct->connect((*m_temp.m_Proxy));
rhs.m_SendDestruct->connect((*m_temp.m_Proxy));
return std::forward<Reactive<decltype(m_Data+rhs.m_Data)> &&>(m_temp);
}
template<class H>
Reactive && operator+(Reactive<H> && rhs)
{
Reactive && m_Temp
}
T & Get()
{
return m_Data;
}
void Update()
{
if(m_Affecter)
m_Data = m_Affecter();
}
void Unreact()
{
m_Affecter = nullptr;
(*m_SendDestruct)();
}
private:
std::unique_ptr<boost::signals2::signal<void()> > m_SendDestruct;
std::shared_ptr<Proxy> m_Proxy;
Slot m_ReceiveDestruct;
std::function<T()> m_Affecter;
T m_Data;
};
そして簡単なテスト
int main()
{
Reactive<int> vel(10);
Reactive<int> acc(5);
Reactive<int> time(5);
Reactive<int> result = vel + acc + time;
system("PAUSE");
return 0;
}
ここに警告/エラーがあります:
1>main.cpp(86): warning C4355: 'this' : used in base member initializer list
1> main.cpp(83) : while compiling class template member function 'Reactive<T>::Reactive(Reactive<T> &&)'
1> with
1> [
1> T=int
1> ]
1> main.cpp(174) : see reference to class template instantiation 'Reactive<T>' being compiled
1> with
1> [
1> T=int
1> ]
1>main.cpp(66): warning C4355: 'this' : used in base member initializer list
1> main.cpp(174) : see reference to function template instantiation 'Reactive<T>::Reactive<int>(const H &)' being compiled
1> with
1> [
1> T=int,
1> H=int
1> ]
1>main.cpp(56): warning C4355: 'this' : used in base member initializer list
1> main.cpp(53) : while compiling class template member function 'Reactive<T>::Reactive(void)'
1> with
1> [
1> T=int
1> ]
1>c:\program files (x86)\boost\boost_1_53_0\boost\signals2\detail\slot_template.hpp(156): error C2248: 'Reactive<T>::Proxy::Proxy' : cannot access private member declared in class 'Reactive<T>::Proxy'
1> with
1> [
1> T=int
1> ]
1> main.cpp(32) : see declaration of 'Reactive<T>::Proxy::Proxy'
1> with
1> [
1> T=int
1> ]
1> main.cpp(30) : see declaration of 'Reactive<T>::Proxy'
1> with
1> [
1> T=int
1> ]
1> c:\program files (x86)\boost\boost_1_53_0\boost\signals2\detail\slot_template.hpp(81) : see reference to function template instantiation 'void boost::signals2::slot0<R,SlotFunction>::init_slot_function<F>(const F &)' being compiled
1> with
1> [
1> R=void,
1> SlotFunction=boost::function<void (void)>,
1> F=Reactive<int>::Proxy
1> ]
1> main.cpp(135) : see reference to function template instantiation 'boost::signals2::slot0<R,SlotFunction>::slot0<Reactive<T>::Proxy>(const F &)' being compiled
1> with
1> [
1> R=void,
1> SlotFunction=boost::function<void (void)>,
1> T=int,
1> F=Reactive<int>::Proxy
1> ]
1> main.cpp(178) : see reference to function template instantiation 'Reactive<T> &&Reactive<T>::operator +<int>(Reactive<T> &)' being compiled
1> with
1> [
1> T=int
1> ]
1>
1>Build FAILED.
1>
1>Time Elapsed 00:00:04.20
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========