c++ - studio - ¿Cómo funciona std:: tie?
hclust r tutorial (2)
Esto no responde a su pregunta de ninguna manera, pero permítame publicarlo de todos modos porque C ++ 17 está básicamente listo (con soporte de compilador), por lo que mientras se pregunta cómo funciona el material desactualizado, probablemente valga la pena ver cómo funciona. futuro, la versión de C ++ también funciona.
Con C ++ 17 puedes rascar bastante
std::tie
a favor de lo que se llama
enlaces estructurados
.
Hacen lo mismo (bueno,
no lo mismo
, pero tienen el mismo efecto neto), aunque necesita escribir menos caracteres, no necesita soporte de biblioteca, y
también
tiene la capacidad de tomar referencias, si eso sucede. Lo que quieras.
(Tenga en cuenta que en C ++ 17 los constructores hacen la deducción de argumentos, por lo que
make_tuple
ha vuelto algo superfluo).
int a, b;
std::tie(a, b) = std::make_tuple(2, 3);
// C++17
auto [c, d] = std::make_tuple(4, 5);
auto [e, f] = std::tuple(6, 7);
std::tuple t(8,9); auto& [g, h] = t; // not possible with std::tie
He usado
std::tie
sin pensarlo mucho.
Funciona, así que acabo de aceptar que:
auto test()
{
int a, b;
std::tie(a, b) = std::make_tuple(2, 3);
// a is now 2, b is now 3
return a + b; // 5
}
¿Pero cómo funciona esta
magia negra
?
¿Cómo un temporal creado por
std::tie
cambia
b
?
Esto me parece más interesante ya que es una función de biblioteca, no una función de lenguaje, por lo que seguramente es algo que podemos implementar y comprender.
Para aclarar el concepto central, redujémoslo a un ejemplo más básico.
Aunque
std::tie
es útil para funciones que devuelven (una tupla de) más valores, podemos entenderlo bien con solo un valor:
int a;
std::tie(a) = std::make_tuple(24);
return a; // 24
Cosas que necesitamos saber para seguir adelante:
-
std::tie
construye y devuelve una tupla de referencias. -
std::tuple<int>
ystd::tuple<int&>
son 2 clases completamente diferentes, sin conexión entre ellas, aparte de que se generaron a partir de la misma plantilla,std::tuple
. -
tupla tiene un
operator=
aceptar una tupla de diferentes tipos (pero el mismo número), donde cada miembro se asigna individualmente, desde cppreference :template< class... UTypes > tuple& operator=( const tuple<UTypes...>& other );
(3) Para todo i, asigna
std::get<i>(other)
astd::get<i>(*this)
.
El siguiente paso es deshacerse de esas funciones que solo se interponen en su camino, para que podamos transformar nuestro código a esto:
int a;
std::tuple<int&>{a} = std::tuple<int>{24};
return a; // 24
El siguiente paso es ver exactamente qué sucede dentro de esas estructuras.
Para esto, creo 2 tipos de sustituyentes
T
para
std::tuple<int>
y sustituyentes
Tr
std::tuple<int&>
, despojados al mínimo para nuestras operaciones:
struct T { // substituent for std::tuple<int>
int x;
};
struct Tr { // substituent for std::tuple<int&>
int& xr;
auto operator=(const T& other)
{
// std::get<I>(*this) = std::get<I>(other);
xr = other.x;
}
};
auto foo()
{
int a;
Tr{a} = T{24};
return a; // 24
}
Y finalmente, me gusta deshacerme de todas las estructuras (bueno, no es 100% equivalente, pero es lo suficientemente cercano para nosotros y lo suficientemente explícito como para permitirlo):
auto foo()
{
int a;
{ // block substituent for temporary variables
// Tr{a}
int& tr_xr = a;
// T{24}
int t_x = 24;
// = (asignement)
tr_xr = t_x;
}
return a; // 24
}
Básicamente,
std::tie(a)
inicializa una referencia de miembro de datos a
a
.
std::tuple<int>(24)
crea un miembro de datos con valor
24
, y la asignación asigna 24 a la referencia del miembro de datos en la primera estructura.
Pero dado que ese miembro de datos es una referencia vinculada a
a
, que básicamente asigna
24
a
a
.