J'ai l'extrait de code suivant:
template <size_t N>
foo make() { ... }
...
for (...) {
auto foo = make<1>();
// lots of tests involving foo
}
Je voudrais répéter ce dernier bloc avec des valeurs différentes pour le paramètre de modèle non-type à make , par exemple, make , make , etc.
Si c'était un type que je voulais parcourir, je pourrais utiliser cette solution , mais il n'est pas clair que je puisse utiliser des paramètres de modèle non-type avec un lambda générique de la même manière.
Comment puis-je prendre en compte cela pour que je puisse créer exécuter le bloc de code ci-dessus mais instancier make avec des valeurs différentes pour son paramètre non-type. La solution ne doit utiliser que des éléments à portée de bloc - c'est facile si je peux créer un objet template de niveau supérieur pour envelopper make code >.
3 Réponses :
Comme point de départ avec la liste d'index fabriqués à la main:
template < size_t FIRST, size_t LAST >
void ExecuteAndTest_Impl()
{
auto foo = make<FIRST>();
std::cout << "Here we go with the test" << foo << std::endl;
// go for next step
if constexpr ( LAST!= FIRST) { ExecuteAndTest_Impl<FIRST+1, LAST>(); }
}
template < size_t LAST >
void ExecuteAndTest()
{
ExecuteAndTest_Impl<1,LAST>();
}
int main()
{
// or always start with 1 to n inclusive
ExecuteAndTest<3>();
}
ou vous pouvez simplement le rendre récursif et utiliser l'index en premier et en dernier comme ceci:
template < size_t FIRST, size_t LAST >
void ExecuteAndTest()
{
auto foo = make<FIRST>();
std::cout << "Here we go with the test" << foo << std::endl;
// go for next step
if constexpr ( LAST != FIRST ) { ExecuteAndTest<FIRST+1, LAST>(); }
}
int main()
{
// first and last index of integer sequence
ExecuteAndTest<1,3>();
}
Dans ce genre de situation, le bon outil consiste à utiliser std :: integer_sequence imprime 1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include <utility>
template <size_t N>
void make()
{
std::cout << N << std::endl;
}
template <size_t... I>
void do_make_helper(std::index_sequence<I...>)
{
(make<I+1>(), ...);
}
template <std::size_t N>
void do_make()
{
do_make_helper(std::make_index_sequence<N>());
}
int main()
{
do_make<10>();
}
Vous pouvez essayer ceci:
#include <utility>
#include <cassert>
struct Foo
{
Foo() {}
Foo(std::size_t i) : i(i) {}
std::size_t i;
};
template <std::size_t... Is>
void setFoo(std::size_t i, Foo& foo, std::index_sequence<Is...>)
{
((i == Is && (foo = Foo{Is}, false)), ...);
}
int main()
{
for (std::size_t i = 0; i < 10; i++)
{
Foo foo;
setFoo(i, foo, std::make_index_sequence<10>{});
assert(foo.i == i);
}
}
Alors, avez-vous un index de terminaison? Et êtes-vous sûr de vouloir commencer à 1 plutôt qu'à 0?
@NicolBolas - dans ce cas, je veux commencer à 1, mais si une solution avec 0 est beaucoup plus propre, je peux m'y adapter. L'index de terminaison est ~ 10, mais je suis également d'accord pour lister les cas à la main, comme
quelque chose {bar <1>, bar <2>, ...}ou autre (mais pas dupliquer tout le code dans la bouclefor).