Странное выражение "- > * [] " в исходном коде cpp на C++.библиотека реагировать


вот фрагмент кода C++, который я нашел в документации cpp.библиотека реакций:

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

Я никогда не видел ->* [] нотации. Во-первых, я думал, что это просто опечатка, но я также нашел такое выражение в исходный код:

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

это действительно C++11 (или C++14)? Что это значит?

3 54

3 ответа:

единственный пример на связанной странице, где я вижу ->* это:

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() перегружает оператор указателя на член->*, и вторым аргументом для этого перегруженного оператора является объект функции, т. е. лямбда-выражение.

Что касается этого примера:

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

Я предполагаю, какие типы width,height & depth are, перегрузка оператора запятой, и результат дает тот же тип, что MakeVar дает, или другой тип, что перегрузки ->*. Остальное-то же самое, что и в первом примере.

@ответ Преториана является правильным. этой - это код из cpp.реагировать

///////////////////////////////////////////////////////////////////////////////////////////////////
/// 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)) и функтор (лямбда)

и свободная функция operator,, который принимает два сигнала

(автор)

во-первых, преторианцы отвечают правильно, но я хотел бы немного уточнить.

обратите внимание, что эта библиотека все еще очень экспериментальная, и я все еще работаю над документацией. Текущее состояние указанной документации можно найти в 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()

это своего рода привязка (сигналы привязки как вход функции), но это не то же самое, что обратный std::bind. объем не является объектом function. В частности, объем не пересчитывается при вызове Value (), он пересчитывается при изменении одного из его зависимых сигналов, результат сохраняется, а Value () возвращает его. Таким образом, это по существу push - распространение изменений с некоторыми дополнительными функциями (без избыточных обновлений, без сбоев, необязательных неявных распараллеливание.)

проблема в том, что 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);

никто не хочет читать подобное, верно? По крайней мере, я не хочу.

таким образом, есть альтернативный синтаксис, который перемещает зависимости влево, обернутый 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; };

проблема с этим, как уже отмечалось, является что любой, кто видит его в первый раз, не знает, что, черт возьми, происходит.

С другой стороны, подключение сигналов к функциям должно быть очень распространенной задачей при использовании этой библиотеки. Как только вы знаете, что он делает, версия ->* более лаконична и визуализирует график потока данных (ребра от ширины и высоты до временной области, ребра от области и глубины до объема).