Ma question est dans le code:
template<typename... Ts>
struct TupleOfVectors {
std::Tuple<std::vector<Ts>...> Tuple;
void do_something_to_each_vec() {
//Question: I want to do this:
// "for each (N)": do_something_to_vec<N>()
//How?
}
template<size_t N>
void do_something_to_vec() {
auto &vec = std::get<N>(Tuple);
//do something to vec
}
};
Vous pouvez le faire assez facilement avec certains mécanismes d'indices. Étant donné une méta-fonction gen_seq
pour générer des séquences entières au moment de la compilation (encapsulées par le modèle de classe seq
):
namespace detail
{
template<int... Is>
struct seq { };
template<int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
template<int... Is>
struct gen_seq<0, Is...> : seq<Is...> { };
}
Et les modèles de fonctions suivants:
#include <Tuple>
namespace detail
{
template<typename T, typename F, int... Is>
void for_each(T&& t, F f, seq<Is...>)
{
auto l = { (f(std::get<Is>(t)), 0)... };
}
}
template<typename... Ts, typename F>
void for_each_in_Tuple(std::Tuple<Ts...> const& t, F f)
{
detail::for_each(t, f, detail::gen_seq<sizeof...(Ts)>());
}
Vous pouvez utiliser le for_each_in_Tuple
fonction au-dessus de cette façon:
#include <string>
#include <iostream>
struct my_functor
{
template<typename T>
void operator () (T&& t)
{
std::cout << t << std::endl;
}
};
int main()
{
std::Tuple<int, double, std::string> t(42, 3.14, "Hello World!");
for_each_in_Tuple(t, my_functor());
}
Voici un ( exemple en direct .
Dans votre situation concrète, voici comment vous pouvez l'utiliser:
template<typename... Ts>
struct TupleOfVectors
{
std::Tuple<std::vector<Ts>...> t;
void do_something_to_each_vec()
{
for_each_in_Tuple(t, Tuple_vector_functor());
}
struct Tuple_vector_functor
{
template<typename T>
void operator () (T const &v)
{
// Do something on the argument vector...
}
};
};
Et encore une fois, voici un exemple en direct .
En C++ 17, vous pouvez faire ceci:
std::apply([](auto ...x){std::make_Tuple(some_function(x)...);} , the_Tuple);
étant donné que some_function
a des surcharges appropriées pour tous les types du Tuple.
Cela fonctionne déjà dans Clang ++ 3.9, en utilisant std::experimental::apply
.
En plus de la réponse de @M. Alaggan, si vous avez besoin d'appeler une fonction sur des éléments Tuple par ordre d'apparition† dans le Tuple, en C++ 17, vous pouvez également utiliser une expression de repli comme celle-ci:
std::apply([](auto& ...x){(..., some_function(x));}, the_Tuple);
( exemple en direct ).
†Parce que sinon l'ordre d'évaluation des arguments de la fonction n'est pas spécifié .
Voici une approche qui peut bien fonctionner dans votre cas:
template<typename... Ts>
struct TupleOfVectors {
std::Tuple<std::vector<Ts>...> Tuple;
void do_something_to_each_vec()
{
// First template parameter is just a dummy.
do_something_to_each_vec_helper<0,Ts...>();
}
template<size_t N>
void do_something_to_vec()
{
auto &vec = std::get<N>(Tuple);
//do something to vec
}
private:
// Anchor for the recursion
template <int>
void do_something_to_each_vec_helper() { }
// Execute the function for each template argument.
template <int,typename Arg,typename...Args>
void do_something_to_each_vec_helper()
{
do_something_to_each_vec_helper<0,Args...>();
do_something_to_vec<sizeof...(Args)>();
}
};
La seule chose qui est un peu désordonnée ici est le paramètre de modèle int
extra factice pour do_something_to_each_vec_helper
. Il est nécessaire de faire de do_something_to_each_vec_helper un modèle lorsqu'il ne reste aucun argument. Si vous vouliez utiliser un autre paramètre de modèle, vous pouvez l’utiliser à la place.
Si vous n'êtes pas particulièrement lié à une solution sous la forme d'un modèle de fonction générique "pour chaque", vous pouvez en utiliser un comme celui-ci:
#ifndef Tuple_OF_VECTORS_H
#define Tuple_OF_VECTORS_H
#include <vector>
#include <Tuple>
#include <iostream>
template<typename... Ts>
struct TupleOfVectors
{
std::Tuple<std::vector<Ts>...> Tuple;
template<typename ...Args>
TupleOfVectors(Args... args)
: Tuple(args...){}
void do_something_to_each_vec() {
do_something_to_vec(Tuple);
}
template<size_t I = 0, class ...P>
typename std::enable_if<I == sizeof...(P)>::type
do_something_to_vec(std::Tuple<P...> &) {}
template<size_t I = 0, class ...P>
typename std::enable_if<I < sizeof...(P)>::type
do_something_to_vec(std::Tuple<P...> & parts) {
auto & part = std::get<I>(Tuple);
// Doing something...
std::cout << "vector[" << I << "][0] = " << part[0] << std::endl;
do_something_to_vec<I + 1>(parts);
}
};
#endif // EOF
Un programme de test, construit avec GCC 4.7.2 et clang 3.2:
#include "Tuple_of_vectors.h"
using namespace std;
int main()
{
TupleOfVectors<int,int,int,int> vecs(vector<int>(1,1),
vector<int>(2,2),
vector<int>(3,3),
vector<int>(4,4));
vecs.do_something_to_each_vec();
return 0;
}
Le même style de récursivité peut être utilisé dans un modèle de fonction générique "for_each" sans appareil d'indices auxiliaires:
#ifndef FOR_EACH_IN_Tuple_H
#define FOR_EACH_IN_Tuple_H
#include <type_traits>
#include <Tuple>
#include <cstddef>
template<size_t I = 0, typename Func, typename ...Ts>
typename std::enable_if<I == sizeof...(Ts)>::type
for_each_in_Tuple(std::Tuple<Ts...> &, Func) {}
template<size_t I = 0, typename Func, typename ...Ts>
typename std::enable_if<I < sizeof...(Ts)>::type
for_each_in_Tuple(std::Tuple<Ts...> & tpl, Func func)
{
func(std::get<I>(tpl));
for_each_in_Tuple<I + 1>(tpl,func);
}
#endif //EOF
Et un programme de test pour ça:
#include "for_each_in_Tuple.h"
#include <iostream>
struct functor
{
template<typename T>
void operator () (T&& t)
{
std::cout << t << std::endl;
}
};
int main()
{
auto tpl = std::make_Tuple(1,2.0,"Three");
for_each_in_Tuple(tpl,functor());
return 0;
}
Je testais avec des tuples et de la métaprogrammation et j'ai trouvé le thread actuel. Je pense que mon travail peut inspirer quelqu'un d'autre bien que j'aime la solution de @Andy.
Quoi qu'il en soit, amusez-vous!
#include <Tuple>
#include <type_traits>
#include <iostream>
#include <sstream>
#include <functional>
template<std::size_t I = 0, typename Tuple, typename Func>
typename std::enable_if< I != std::Tuple_size<Tuple>::value, void >::type
for_each(const Tuple& Tuple, Func&& func)
{
func(std::get<I>(Tuple));
for_each<I + 1>(Tuple, func);
}
template<std::size_t I = 0, typename Tuple, typename Func>
typename std::enable_if< I == std::Tuple_size<Tuple>::value, void >::type
for_each(const Tuple& Tuple, Func&& func)
{
// do nothing
}
struct print
{
template<typename T>
void operator () (T&& t)
{
std::cout << t << std::endl;
}
};
template<typename... Params>
void test(Params&& ... params)
{
int sz = sizeof...(params);
std::Tuple<Params...> values(std::forward<Params>(params)...);
for_each(values, print() );
}
class MyClass
{
public:
MyClass(const std::string& text)
: m_text(text)
{
}
friend std::ostream& operator <<(std::ostream& stream, const MyClass& myClass)
{
stream << myClass.m_text;
return stream;
}
private:
std::string m_text;
};
int main()
{
test(1, "hello", 3.f, 4, MyClass("I don't care") );
}