wyer33
¿Hay una buena manera de usar std::tie
y crear una nueva variable de una sola vez? En otras palabras, si una función devuelve un std::tuple
y queremos finalmente dividir el resultado en componentes individuales, ¿hay alguna manera de hacer estas asignaciones sin definir las variables de antemano?
Por ejemplo, considere el siguiente código:
#include <tuple>
struct Foo {
Foo(int) {}
};
struct Bar{};
std::tuple <Foo,Bar> example() {
return std::make_tuple(Foo(1),Bar());
}
int main() {
auto bar = Bar {};
// Without std::tie
{
auto foo_bar = example();
auto foo = std::get<0>(std::move(foo_bar));
bar = std::get<1>(std::move(foo_bar));
}
// With std::tie
#if 0
{
// Error: no default constructor
Foo foo;
std::tie(foo,bar) = example();
}
#endif
}
Básicamente, la función example
devuelve una tupla. Ya tenemos una variable de tipo Bar
que queremos asignar, pero necesitamos una nueva variable de tipo Foo
. Sin std::tie
no necesitamos crear una instancia ficticia de Foo
pero el código requiere que pongamos todo en un std::tuple
primero y luego dividirlo. Con std::tie
tenemos que asignar un dummy Foo
primero, pero no tenemos un constructor predeterminado para hacerlo. En realidad, pretendemos que los constructores de Foo
son complicados, por lo que no es deseable crear primero un valor ficticio. En última instancia, nos gustaría asignar en ambos foo
y bar
pero quiere hacer esta asignación y asignar memoria para Foo
al mismo tiempo.
Moncef Mechri
Esta característica se llama encuadernaciones estructuradas en C++17. Muy bienvenida adición!
Ejemplo de uso:
#include <iostream>
#include <tuple>
int main()
{
auto tuple = std::make_tuple(1, 'a', 2.3);
// unpack the tuple into individual variables declared at the call site
auto [ i, c, d ] = tuple;
std::cout << "i=" << i << " c=" << c << " d=" << d << '\n';
return 0;
}
Probado en GCC 7.2 con -std=c++17
.
-
Impresionante característica.
– Ciro Santilli OurBigBook.com
23 de diciembre de 2017 a las 19:15
wyer33
@MikaelPersson tenía el enlace correcto. Básicamente, no hay una gran manera de hacer esto. Sin embargo, hay algunas formas inteligentes basadas en N3802. Es decir, utilizar
// This comes from the N3802 proposal for C++
template <typename F, typename Tuple, size_t... I>
decltype(auto) apply_impl(F&& f, Tuple&& t, std::index_sequence<I...>) {
return std::forward<F>(f)(std::get<I>(std::forward<Tuple>
}
template <typename F, typename Tuple>
decltype(auto) apply(F&& f, Tuple&& t) {
using Indices =
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>;
return apply_impl(std::forward<F>(f), std::forward<Tuple>
}
A continuación, escribir
// With compose
{
auto foo = apply([&bar](auto && foo,auto && bar_) {
bar=std::move(bar_);
return std::move(foo);
}, example());
}
Y, sí, todo esto es feo, pero la situación surgió en algún momento que tuve. Sin embargo, como muestra el enlace de @MikaelPersson, este es un problema general y aún no está completamente resuelto.
me duele la cabeza al leer el código, que es una señal segura de que se requiere una lógica más simple. La respuesta corta es no. devolver una tupla de valores es una forma muy eficiente de devolver y asignar. tie:: solo está ahí para desempaquetar valores. Si debe hacer esto, considere atarlo a un
boost::optional<Foo>
-Richard Hodges
28 de marzo de 2015 a las 0:31
El hecho de que
Bar
contiene unaFoo
parece ser una configuración para una falla. Una vez que te divorcies (extracto)Foo
deBar
que el 50% deBar
se convierte en “válido pero potencialmente indeterminado / no especificado de otra manera”.– mal
28 de marzo de 2015 a las 0:35
Una forma de evitar la necesidad de separarlos es para cualquier otra clase que solía dividir un
Foo
a partir de unaBar
simplemente aceptar unBar
y usar su miembroFoo
o para mantenerBar
vivo y pasar referencias aFoo
.– mal
28 de marzo de 2015 a las 0:37
Hubo una discusión relacionada sobre una posible propuesta relacionada con este problema, échale un vistazo aquí: groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/…
– Mikael Personson
28 de marzo de 2015 a las 4:56
Debido a que la ‘asignación de memoria’ generalmente se refiere a la asignación de memoria dinámica, reformulé la pregunta en términos de definición/creación de variables. ¿Puedo sugerirle que reduzca su ejemplo? Creo que muchas cosas son innecesarias. Creo que la esencia de lo que buscas se puede resumir en algo como esto.
–Luc Danton
28 de marzo de 2015 a las 12:32