Variadic template [résolu]

Variadic template [résolu] - C++ - Programmation

Marsh Posté le 13-08-2015 à 11:16:30    

Bonjour,
 
Un petit code vaut mieux qu'un long discours:

Code :
  1. #include <iostream>
  2. #include <tuple>
  3. static int i(0);
  4. template <typename T>
  5. T getOneElement()
  6. {
  7.     return static_cast<T>(i++);
  8. }
  9. template <typename... Data>
  10. std::tuple<Data...> test()
  11. {
  12.     return std::make_tuple(getOneElement<Data>()...);
  13. }
  14. int main(int argc, char ** argv)
  15. {
  16.     std::tuple<double, double, float, int> t4(test<double, double, float, int>());
  17.     std::cout<<std::get<0>(t4)<<" "<<std::get<1>(t4)<<" "<<std::get<2>(t4)<<" "<<std::get<3>(t4)<<std::endl;
  18.     return 0;
  19. }


 
Pourquoi ce code m'affiche-t-il
3 2 1 0
Au lieu de
0 1 2 3
?
 
Y'a-t-il un moyen d'inverser ce résultat?
 
Merci.


Message édité par ptitchep le 13-08-2015 à 13:33:57

---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 13-08-2015 à 11:16:30   

Reply

Marsh Posté le 13-08-2015 à 13:01:44    

je pense pas que l'ordre d'évaluation des arguments de make_tuple soit clairement défini (ca mériterait de vérifier dans le standard, mais j'y crois moyennement).
Si tu tiens absolument à avoir un contrôle sur cet ordre, je pense qu'il va falloir réécrire make_tuple toi-même. (mais honnêtement, j'ai l'impression que ce n'est pas une très bonne idée d'avoir du code qui repose sur l'ordre d'évaluation des arguments de ton tuple à sa création).


---------------
last.fm
Reply

Marsh Posté le 13-08-2015 à 13:33:22    

theshockwave a écrit :

je pense pas que l'ordre d'évaluation des arguments de make_tuple soit clairement défini (ca mériterait de vérifier dans le standard, mais j'y crois moyennement).
Si tu tiens absolument à avoir un contrôle sur cet ordre, je pense qu'il va falloir réécrire make_tuple toi-même. (mais honnêtement, j'ai l'impression que ce n'est pas une très bonne idée d'avoir du code qui repose sur l'ordre d'évaluation des arguments de ton tuple à sa création).


Apparemment Le standard C (je pense que c'est le même en C++) dit que les arguments sont évalués de droite à gauche, ce qui est cohérent avec mon résultat.
Problème résolu comme ceci, mais c'est encore moins lisible:

Code :
  1. #include <iostream>
  2. #include <tuple>
  3. static int i(0);
  4. template <typename T>
  5. T getOneElement() {
  6.     return static_cast<T>(i++);
  7. }
  8. template <typename T>
  9. std::tuple<T> test()
  10. {
  11.     return std::make_tuple(getOneElement<T>());
  12. }
  13. template <typename T, typename T2, typename... Data>
  14. std::tuple<T, T2, Data...> test()
  15. {
  16.     std::tuple<T> head = std::make_tuple(getOneElement<T>());
  17.     std::tuple<T2, Data...> tail = test<T2, Data...>();
  18.     return std::tuple_cat(head, tail);
  19. }
  20. int main(int argc, char ** argv)
  21. {
  22.     std::tuple<double, double, float, int> t4(test<double, double, float, int>());
  23.     std::cout<<std::get<0>(t4)<<" "<<std::get<1>(t4)<<" "<<std::get<2>(t4)<<" "<<std::get<3>(t4)<<std::endl;
  24.     return 0;
  25. }


Message cité 1 fois
Message édité par ptitchep le 13-08-2015 à 13:33:39

---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 13-08-2015 à 14:20:33    

ptitchep a écrit :


Apparemment Le standard C (je pense que c'est le même en C++) dit que les arguments sont évalués de droite à gauche, ce qui est cohérent avec mon résultat.
Problème résolu comme ceci, mais c'est encore moins lisible:

Code :
  1. #include <iostream>
  2. #include <tuple>
  3. static int i(0);
  4. template <typename T>
  5. T getOneElement() {
  6.     return static_cast<T>(i++);
  7. }
  8. template <typename T>
  9. std::tuple<T> test()
  10. {
  11.     return std::make_tuple(getOneElement<T>());
  12. }
  13. template <typename T, typename T2, typename... Data>
  14. std::tuple<T, T2, Data...> test()
  15. {
  16.     std::tuple<T> head = std::make_tuple(getOneElement<T>());
  17.     std::tuple<T2, Data...> tail = test<T2, Data...>();
  18.     return std::tuple_cat(head, tail);
  19. }
  20. int main(int argc, char ** argv)
  21. {
  22.     std::tuple<double, double, float, int> t4(test<double, double, float, int>());
  23.     std::cout<<std::get<0>(t4)<<" "<<std::get<1>(t4)<<" "<<std::get<2>(t4)<<" "<<std::get<3>(t4)<<std::endl;
  24.     return 0;
  25. }




 
Tu parles de l'ordre d'évaluation des arguments lors d'un appel à une fonction, ici, c'est un cas très différent, c'est pour ca que je t'encourageais à regarder ce que le standard dit spécifiquement à propos de make_tuple.


---------------
last.fm
Reply

Marsh Posté le 13-08-2015 à 14:25:10    

theshockwave a écrit :


 
Tu parles de l'ordre d'évaluation des arguments lors d'un appel à une fonction, ici, c'est un cas très différent, c'est pour ca que je t'encourageais à regarder ce que le standard dit spécifiquement à propos de make_tuple.


Ici c'est bien l'appel à make_tuple qui est fait en donnant mes arguments en "sens inverse" non? Je ne comprends pas pourquoi ce serait un cas différent.


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 13-08-2015 à 14:31:27    

ptitchep a écrit :


Ici c'est bien l'appel à make_tuple qui est fait en donnant mes arguments en "sens inverse" non? Je ne comprends pas pourquoi ce serait un cas différent.


 
C'est différent en ce que ca donne lieu à la génération de code qui va itérer sur tes arguments. Ca ne donne pas lieu à un simple appel de fonction où l'ordre des arguments est défini. De la manière dont cette itération est faite va dépendre l'ordre d'évaluation de tes quatre appels à ta fonction getOneElement()


---------------
last.fm
Reply

Marsh Posté le 13-08-2015 à 15:06:42    

Ok je vois. J'avoue que je ne sais pas si j'aurai le courage d'aller lire ça. Pour les prochains s'il y en a, d'après cppreference:
References:
    C++11 standard (ISO/IEC 14882:2011):  
        20.4 Tuples [tuple]  
http://en.cppreference.com/w/cpp/utility/tuple


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 13-08-2015 à 15:12:12    

Manifestement, il ne dit rien.
 
Mais par contre, je reste dubitatif:
template <typename... Data> std::tuple<Data...> test() {
    // return std::make_tuple(getOneElement<Data>()...);
    return std::tuple<Data...>{ getOneElement<Data>()... };
}
 
Ne marche pas mieux, or d'après cette page, ça devrait coller:

Citation :

The use of brace initialization works because the order of evaluation of the arguments in a brace initializer list is the order in which they appear.


 
A+,


---------------
There's more than what can be linked! --    Iyashikei Anime Forever!    --  AngularJS c'est un framework d'engulé!  --
Reply

Marsh Posté le 28-08-2015 à 08:42:35    

Des infos relatives à ces histoires d'ordre d'évaluation (dans un contexte different mais simialire) :
 
https://www.youtube.com/watch?v=Pr9g1nqTz_A

Reply

Marsh Posté le 22-11-2015 à 17:21:57    

Joel F a écrit :

Des infos relatives à ces histoires d'ordre d'évaluation (dans un contexte different mais simialire) :
 
https://www.youtube.com/watch?v=Pr9g1nqTz_A


 
Félicitations pour ton talk à CppCon. :jap:  
https://www.youtube.com/watch?v=IiVl5oSU5B8


---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed