equal - overload c++ operator
Extraña expresión "->*[]" en el código fuente C++ de la biblioteca cpp.react (3)
(Autor aquí)
En primer lugar, la respuesta de los pretorianos es correcta, pero me gustaría explayarme un poco.
Tenga en cuenta que esta biblioteca todavía es muy experimental y todavía estoy trabajando en la documentación. El estado actual de dicha documentación se puede encontrar en la wiki, en particular https://github.com/schlangster/cpp.react/wiki/User-Guide-%7C-Signals está relacionado con la pregunta.
Aquí hay un ejemplo más detallado:
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()
Es una especie de enlace (enlace de señales como entrada de función), pero NO es lo mismo que un enlace inverso std :: bind. el volumen no es un objeto de función. En particular, el volumen no se vuelve a calcular cuando se llama a Value (), se vuelve a calcular cuando una de sus señales dependientes cambia, el resultado se guarda y Value () lo devuelve. Por lo tanto, se trata esencialmente de una propagación de cambios basada en el empuje con algunas características adicionales (sin actualizaciones redundantes, sin problemas técnicos, paralelización implícita opcional).
El problema es que MakeSignal se vuelve confuso cuando se mezcla con señales temporales y 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);
Nadie quiere leer cosas así, ¿verdad? Al menos no quiero.
Entonces hay una sintaxis alternativa que mueve las dependencias hacia la izquierda, envuelto por 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; });
Y, finalmente, con la coma malvada y -> * sobrecargas:
D::SignalT<int> volume =
(
(width, height) ->* [] (int w, int h) { return w * h; },
depth
)
->* [] (int area, int d) { return a * d; };
El problema con esto, como han notado otros, es que cualquiera que lo vea por primera vez no sabe qué diablos está pasando.
Por otro lado, conectar señales a funciones debería ser una tarea muy común al usar esta biblioteca. Una vez que sepa lo que hace, la versión -> * es más concisa y visualiza el gráfico de flujo de datos (bordes desde el ancho y alto hasta el área temporal, bordes desde el área y profundidad hasta el volumen).
Aquí hay un fragmento de C ++ que encontré en la documentación de la biblioteca cpp.react :
auto in = D::MakeVar(0);
auto op1 = in ->* [] (int in)
{
int result = in /* Costly operation #1 */;
return result;
};
Nunca he visto la notación ->* []
. Primero, pensé que era solo un error tipográfico, pero también encontré esa expresión en el código fuente :
auto volume = (width,height,depth) ->* [] (int w, int h, int d) {
return w * h * d;
};
¿Es esto C ++ 11 válido (o C ++ 14)? Qué significa eso?
El único ejemplo en la página vinculada donde veo ->*
es esto:
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;
};
Aquí está mi suposición: cualquier tipo devuelto por D::MakeVar()
sobrecarga el operador de puntero a miembro ->*
, y el segundo argumento para ese operador sobrecargado es un objeto de función, es decir, la expresión lambda.
En cuanto a este ejemplo:
auto volume = (width,height,depth) ->* [] (int w, int h, int d) {
return w * h * d;
};
Supongo que cualquiera que sea el width
, el height
y la depth
, sobrecargo al operador de coma, y el resultado arroja el mismo tipo que el rendimiento de MakeVar
, o de otro tipo que sobrecarga ->*
. El resto es el mismo que el primer ejemplo.
La respuesta de @ Praetorian es correcta. This es el código de 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);
}
como se puede ver, el operator->*
función libre está sobrecargado operator->*
que toma una señal ( D::MakeVar(0)
) y un funtor (lambda)
y operator,
función libre operator,
que toma dos señales