奇怪的" - >*[]"表达式在cpp.react库的C++源代码中

Phi*_*ßen 55 c++ language-lawyer c++11 operator-arrow-star

这是我在cpp.react库的文档中找到的C++代码段:

auto in = D::MakeVar(0);
auto op1 = in ->* [] (int in)
{
    int result = in /* Costly operation #1 */;
    return result;
};
Run Code Online (Sandbox Code Playgroud)

我从未见过这种->* []符号.首先,我认为这只是一个错字,但我也在源代码中找到了这样一个表达式:

auto volume = (width,height,depth) ->* [] (int w, int h, int d) {
    return w * h * d;
};
Run Code Online (Sandbox Code Playgroud)

这是有效的C++ 11(或C++ 14)吗?这是什么意思?

Pra*_*ian 42

我看到的链接页面上的唯一示例->*是:

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;
};
Run Code Online (Sandbox Code Playgroud)

这是我的猜测 - 指针到成员操作符D::MakeVar()重载返回的任何类型,以及该重载操作符的第二个参数是一个函数对象,即lambda表达式. ->*

至于这个例子:

auto volume = (width,height,depth) ->* [] (int w, int h, int d) {
    return w * h * d;
};
Run Code Online (Sandbox Code Playgroud)

我猜什么类型的width,heightdepth是,重载逗号操作符,结果产生相同类型什么MakeVar收益,或重载另一种类型->*.其余与第一个例子相同.

  • 这太乱了. (32认同)

Bry*_*hen 17

@ 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));
}
Run Code Online (Sandbox Code Playgroud)
///////////////////////////////////////////////////////////////////////////////////////////////////
/// 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);
}
Run Code Online (Sandbox Code Playgroud)

你可以看到它重载了自由函数operator->*,它接受一个signal(D::MakeVar(0))和一个函子(lambda)

和自由功能operator,,需要两个信号


use*_*432 10

(作者在这里)

首先,Praetorians回答是正确的,但我想详细说明一下.

请注意,这个库仍然是非常实验性的,我仍在研究文档.所述文档的当前状态可以在wiki中找到,特别是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()
Run Code Online (Sandbox Code Playgroud)

它是一种绑定(绑定信号作为函数输入),但它与反向std :: bind不同.volume不是函数对象.特别是,当您调用Value()时,不会重新计算音量,当其中一个相关信号发生更改时,将重新计算音量,保存结果,并返回Value().因此它本质上是基于推送的变更传播,具有一些额外的功能(没有冗余更新,没有毛刺,可选的隐式并行化).

问题是MakeSignal在与临时信号和lambdas混合时会变得混乱:

// 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);
Run Code Online (Sandbox Code Playgroud)

没有人想读这样的东西,对吧?至少我不想.

因此,有一种替代语法将依赖项移动到左侧,由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; });
Run Code Online (Sandbox Code Playgroud)

最后,用邪恶的逗号和 - >*重载:

D::SignalT<int> volume =
(
    (width, height) ->* [] (int w, int h) { return w * h; },
    depth
)
->* [] (int area, int d) { return a * d; };
Run Code Online (Sandbox Code Playgroud)

正如其他人所指出的那样,问题在于,第一次看到它的人都不知道到底发生了什么.

另一方面,在使用此库时,将信号连接到函数应该是一项非常常见的任务.一旦你知道它做了什么, - >*版本更简洁,它可视化数据流图(从宽度和高度到临时区域的边缘,从区域和深度到体积的边缘).

  • 我可以建议用命名运算符替换` - >*`吗?`:: SignalT <int> volume =((width,height)*connect_to*[](int w,int h){return w*h;},depth)*connect_to*[](int area,int d){返回a*d; ` - 虽然很神奇,但它可能比` - >*`更容易混淆.你甚至可以`*connect_with*`而不是`,`.(命名运算符是一个标记类型,左手`operator*`重载,它返回一个右手`operator*`重载的包,它调用实际的"operation"函数.我经常将操作函数存储在标记类型中因地方原因.) (2认同)