¿Cómo puedo iterar sobre una tupla (usando C++ 11)? Intenté lo siguiente:
for(int i=0; i<std::tuple_size<T...>::value; ++i)
std::get<i>(my_tuple).do_sth();
pero esto no funciona:
Error 1: lo siento, no implementado: no se puede expandir ‘Oyente…’ en una lista de argumentos de longitud fija.
Error 2: no puedo aparecer en una expresión constante.
Entonces, ¿cómo itero correctamente sobre los elementos de una tupla?

emsr
Tengo una respuesta basada en iterar sobre una tupla:
#include <tuple>
#include <utility>
#include <iostream>
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
print(std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
print(std::tuple<Tp...>& t)
{
std::cout << std::get<I>
print<I + 1, Tp...>
}
int
main()
{
typedef std::tuple<int, float, double> T;
T t = std::make_tuple(2, 3.14159F, 2345.678);
print
}
La idea habitual es utilizar la recursividad en tiempo de compilación. De hecho, esta idea se usa para hacer un printf que sea seguro para escribir, como se indica en los documentos de tupla originales.
Esto se puede generalizar fácilmente en un for_each
para tuplas:
#include <tuple>
#include <utility>
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
for_each(std::tuple<Tp...> &, FuncT) // Unused arguments are given no names.
{ }
template<std::size_t I = 0, typename FuncT, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
for_each(std::tuple<Tp...>& t, FuncT f)
{
f(std::get<I>
for_each<I + 1, FuncT, Tp...>(t, f);
}
Aunque esto requiere un poco de esfuerzo para tener FuncT
representar algo con las sobrecargas apropiadas para cada tipo que pueda contener la tupla. Esto funciona mejor si sabe que todos los elementos de la tupla compartirán una clase base común o algo similar.
En C ++ 17, puede usar std::apply
con expresión de pliegue:
std::apply([](auto&&... args) {((/* args.dosomething() */), ...);}, the_tuple);
Un ejemplo completo para imprimir una tupla:
#include <tuple>
#include <iostream>
int main()
{
std::tuple t{42, 'a', 4.2}; // Another C++17 feature: class template argument deduction
std::apply([](auto&&... args) {((std::cout << args << '\n'), ...);}, t);
}
[Online Example on Coliru]
Esta solución resuelve el problema del orden de evaluación en la respuesta de M. Alaggan.

daniel stek
C++ está introduciendo declaraciones de expansión para este propósito. Originalmente iban por buen camino para C++20, pero no pasaron el corte por poco debido a la falta de tiempo para revisar la redacción del idioma (ver aquí y aquí).
La sintaxis acordada actualmente (consulte los enlaces anteriores) es:
{
auto tup = std::make_tuple(0, 'a', 3.14);
template for (auto elem : tup)
std::cout << elem << std::endl;
}

Éric Malenfant
Boost Fusion es una posibilidad:
Ejemplo no probado:
struct DoSomething
{
template<typename T>
void operator()(T& t) const
{
t.do_sth();
}
};
tuple<....> t = ...;
boost::fusion::for_each(t, DoSomething());
En C++ 17 puedes hacer esto:
std::apply([](auto ...x){std::make_tuple(x.do_something()...);} , the_tuple);
Esto ya funciona en Clang++ 3.9, usando std::experimental::apply.
Use Boost.Hana y lambdas genéricas:
#include <tuple>
#include <iostream>
#include <boost/hana.hpp>
#include <boost/hana/ext/std/tuple.hpp>
struct Foo1 {
int foo() const { return 42; }
};
struct Foo2 {
int bar = 0;
int foo() { bar = 24; return bar; }
};
int main() {
using namespace std;
using boost::hana::for_each;
Foo1 foo1;
Foo2 foo2;
for_each(tie(foo1, foo2), [](auto &foo) {
cout << foo.foo() << endl;
});
cout << "foo2.bar after mutation: " << foo2.bar << endl;
}
http://coliru.stacked-crooked.com/a/27b3691f55caf271
Una forma más simple, intuitiva y fácil de compilar de hacer esto en C++17, usando if constexpr
:
// prints every element of a tuple
template<size_t I = 0, typename... Tp>
void print(std::tuple<Tp...>& t) {
std::cout << std::get<I>
// do things
if constexpr(I+1 != sizeof...(Tp))
print<I+1>
}
Esta es una recursividad en tiempo de compilación, similar a la presentada por @emsr. Pero esto no usa SFINAE, así que (creo) es más fácil de compilar.
¿Puedo preguntar, cómo se compila en C++ 0x? No está lanzado ni listo hasta donde yo sé.
– Burkhard
29 de julio de 2009 a las 6:09
g++ contiene compatibilidad experimental con algunas funciones de C++0X, incluidas plantillas variadas, desde la versión 4.3. Otros compiladores hacen lo mismo (con diferentes conjuntos de características, si desea usarlos en producción, está de regreso en los 90 con una amplia variación de soporte para cosas de última generación)
– Un programador
29 de julio de 2009 a las 7:10
Estoy usando g ++ versión 4.4 con std = c ++ 0x
– 1521237
30 de julio de 2009 a las 10:33
Esta pregunta necesita una actualización de C++ 11.
– Omnifaro
3 de febrero de 2013 a las 4:04
@Omnifarious ahora, necesita una actualización de C++14
– pepper_chico
19 de abril de 2014 a las 15:38