在cpp.react库的C ++源代码中奇怪的“ – > * ”expression式
这里是我在cpp.react库的文档中find的C ++代码片段:
auto in = D::MakeVar(0); auto op1 = in ->* [] (int in) { int result = in /* Costly operation #1 */; return result; };
我从来没有见过->* []
符号。 首先,我认为这只是一个错字,但我也在源代码中find了这样一个expression式:
auto volume = (width,height,depth) ->* [] (int w, int h, int d) { return w * h * d; };
这是有效的C + + 11(或C + + 14)? 这是什么意思?
我看到的链接页面上的唯一例子->*
是这样的:
auto in = D::MakeVar(0); auto op1 = in ->* [] (int in) { int result = in /* Costly operation #1 */; return result; }; auto op2 = in ->* [] (int in) { int result = in /* Costly operation #2 */; return result; };
这里是我的猜测 – 无论D::MakeVar()
重载指针到成员操作符 ->*
types是什么,重载操作符的第二个参数是一个函数对象,即lambdaexpression式。
至于这个例子:
auto volume = (width,height,depth) ->* [] (int w, int h, int d) { return w * h * d; };
我猜无论什么types的width
, height
和depth
,重载逗号运算符,结果产生相同的types作为什么MakeVar
产量,或另一种types重载->*
。 其余与第一个例子相同。
@ Praetorian的答案是正确的。 这是来自cpp.react的代码
/////////////////////////////////////////////////////////////////////////////////////////////////// /// operator->* overload to connect inputs to a function and return the resulting node. /////////////////////////////////////////////////////////////////////////////////////////////////// // Single input template < typename D, typename F, template <typename D_, typename V_> class TSignal, typename TValue, class = std::enable_if< IsSignal<TSignal<D,TValue>>::value>::type > auto operator->*(const TSignal<D,TValue>& inputNode, F&& func) -> Signal<D, typename std::result_of<F(TValue)>::type> { return D::MakeSignal(std::forward<F>(func), inputNode); } // Multiple inputs template < typename D, typename F, typename ... TSignals > auto operator->*(const InputPack<D,TSignals ...>& inputPack, F&& func) -> Signal<D, typename std::result_of<F(TSignals ...)>::type> { return apply( REACT_IMPL::ApplyHelper<D, F&&, TSignals ...>::MakeSignal, std::tuple_cat(std::forward_as_tuple(std::forward<F>(func)), inputPack.Data)); }
/////////////////////////////////////////////////////////////////////////////////////////////////// /// Comma operator overload to create input pack from 2 signals. /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename TLeftVal, typename TRightVal > auto operator,(const Signal<D,TLeftVal>& a, const Signal<D,TRightVal>& b) -> InputPack<D,TLeftVal, TRightVal> { return InputPack<D, TLeftVal, TRightVal>(a, b); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Comma operator overload to append node to existing input pack. /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename ... TCurValues, typename TAppendValue > auto operator,(const InputPack<D, TCurValues ...>& cur, const Signal<D,TAppendValue>& append) -> InputPack<D,TCurValues ... , TAppendValue> { return InputPack<D, TCurValues ... , TAppendValue>(cur, append); }
你可以看到它重载了自由函数operator->*
,它接受一个信号( D::MakeVar(0)
)和一个D::MakeVar(0)
函数(lambda)
和自由functionoperator,
它需要两个信号
(作者在这里)
首先,Praetorians的回答是正确的,但我想详细说一下。
请注意,这个库仍然是非常实验性的,我仍然在处理文档。 所述文档的当前状态可以在wiki中find,特别是https://github.com/schlangster/cpp.react/wiki/User-Guide-%7C-Signals与该问题有关。;
这是一个更详细的例子:
int calcVolume(int w, int h, int d) { return w*h*d; } D::VarSignalT<int> width = D::MakeVar(1); D::VarSignalT<int> height = D::MakeVar(2); D::VarSignalT<int> depth = D::MakeVar(3); D::SignalT<int> volume = MakeSignal(&calcVolume, width, height, depth); Observe(volume, [] (int v) { printf("volume changed to %d\n", v); }); width.Set(10); // => volume changed to 60. printf("volume: %d\n", volume.Value()); // short: volume()
这是一种绑定(绑定信号作为函数input),但它不是相同的反向标准::绑定。 卷不是一个函数对象。 尤其是当您调用Value()时不会重新计算音量,当其中一个相关信号发生变化时重新计算音量,结果被保存,并且Value()返回它。 因此,它基本上是基于推送的变化传播与一些额外的function(没有多余的更新,没有小故障,可选的隐式并行化)。
问题在于,当与临时信号和lambdaexpression式混合时,MakeSignal会变得混乱:
// First create a temporary area signal, then use it as an argument for the volume signal D::SignalT<int> volume = MakeSignal( [] (int a, int d) { return a * d; }, MakeSignal( [] (int w, int h) { return w * h; }, width, height), depth);
没有人想要读这样的东西,对吧? 至less我不想。
所以有一个可选的语法,将依赖关系移到左侧,由SignalList包装。
// Note: Not sure if I have already pushed this variant yet D::SignalT<int> volume = MakeSignalList( MakeSignalList(width, height).Bind([] (int w, int h) { return w * h; }), depth ).Bind([] (int a, int d) { return a * d; });
最后,用逗号和 – > *重载:
D::SignalT<int> volume = ( (width, height) ->* [] (int w, int h) { return w * h; }, depth ) ->* [] (int area, int d) { return a * d; };
正如其他人所指出的那样,这个问题是任何人第一次看到它都不知道发生了什么事情。
另一方面,使用这个库时,将信号连接到函数应该是一个非常普通的任务。 一旦你知道它做了什么, – > *版本更简洁,它可视化数据stream图(从宽度和高度到临时区域的边缘,从区域到深度的边缘)。