c++ std variadic-templates c++17 variant

c++ - ¿Por qué std:: visit toma un número variable de variantes?



variadic-templates c++17 (2)

Para hacer limpiador de múltiples visitas. Digamos que tenía dos std::variant<A,B> , uno con el nombre a la left y otro con el nombre a la right . Con visitas múltiples, puedo escribir:

struct Visitor { void operator()(A, A); void operator()(A, B); void operator()(B, A); void operator()(B, B); }; std::visit(Visitor{}, left, right);

Esa es una interfaz bastante limpia, y es algo que comúnmente es útil. También es fácil de implementar de manera eficiente: simplemente crea una matriz de funciones ndimensional en lugar de una matriz unidimensional.

Por otro lado, con una sola visita, tendrías que escribir:

std::visit([&](auto l_elem){ std::visit([&](auto r_elem){ Visitor{}(l_elem, r_elem); }, right) }, left);

Es miserable escribir, miserable leer, y probablemente menos eficiente también.

Tratando de familiarizarme con C ++ 17, me he dado cuenta de que std::visit :

template <class Visitor, class... Variants> constexpr /*something*/ visit(Visitor&& vis, Variants&&... vars);

¿Por qué std::visit no toma una sola variante, sino más bien cualquier número de variantes? Quiero decir, siempre puede tomar alguna función de biblioteca estándar y hacer que tome múltiples parámetros con el mismo rol, trabajando en todos ellos (por ejemplo, std::find() para múltiples elementos en un contenedor); o podría estar recibiendo varios visitantes y usándolos en la misma variante.

Entonces, ¿por qué esta ''variadificación'' específica?


Porque necesitamos permitir visitas de combinaciones de clases dentro de variantes. Es decir, si tenemos

using Var1 = std::variant<A,B>; using Var2 = std::variant<C,D>;

Obviamente podemos utilizar este tipo de visitantes:

struct Visitor1 { void operator()(A); void operator()(B); }; struct Visitor2 { void operator()(C); void operator()(D); };

con Var1 y Var2 respectivamente. Incluso podemos usar este tipo siguiente, con Var1 y Var2 individualmente:

struct Visitor3 { void operator()(A); void operator()(B); void operator()(C); void operator()(D); };

pero lo que falta es que queramos poder visitar uno de los cuatro pares (A,C) , (A,D) , (B,C) , (B,D) - cuando miramos un par de Var1 y Var2 juntos . Es por eso que el argumento variad para std::visit es todo menos necesario. Un visitante apropiado se vería así:

struct Visitor4 { void operator()(A,C); void operator()(A,D); void operator()(B,C); void operator()(B,D); };

y llamaríamos std::visit(Visitor4{}, my_var1_instance, my_var2_instance);

Me di cuenta de esto al leer la respuesta de Barry .