Partage
  • Partager sur Facebook
  • Partager sur Twitter

Le compilateur ne peut pas déduire les types.

Extraction des types d'un std::tuple dans une fonction.

Sujet résolu
    8 juin 2021 à 23:46:22

    Salut!

    Je pensais que ce code compilerait mais il m'indique qu'il ne peux pas déduire les types extrait du std::tuple ici :

    template <size_t I=0, size_t... Ints>
        requires (I == std::tuple_size<T>())
        static constexpr auto func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints+I-1>(T())())...>()) {
            return get<decltype(std::get<Ints+I-1>(T())())...>();
    
        }

    Dans ce code-ci (un code que j'ai écris juste pour faire des essais) :

    template <typename C>
    struct contains {
        template <typename A>
        requires std::derived_from<std::is_same<C, A>, std::true_type>
        static constexpr std::true_type c () {
            return std::true_type();
        }
        template <typename A>
        requires std::derived_from<std::is_same<C, A>, std::false_type>
        static constexpr std::false_type c () {
            return std::false_type();
        }
        template <size_t I, size_t S, class A, class... xs>
        requires (c() || I == 0)
        static constexpr auto func() -> decltype(c<A>()) {
            return c<A>();
    
        }
        template <size_t I, size_t S, class A, class... xs>
        requires (!c<A>() && I != S-1)
        static constexpr auto const func() -> decltype(func<I-1, sizeof...(xs), xs...>()) {
            return func<I-1, sizeof...(xs), xs...>();
        }
        template <size_t I, size_t S, class... xs>
        requires (I == S-1)
        static constexpr auto func() -> decltype(func<I-1, sizeof...(xs), xs...>()) {
            return func<I-1, sizeof...(xs), xs...>();
        }
    };
    struct identity {
        template <class x>
        using type = x;
    };
    template <class... A>
    struct list {
        using type = std::tuple<A...>;
    };
    template <template <class...> class L, class A, class... Args>
    struct push_front {
        using type = L<A, Args...>;
    };
    template<class C, template<class> class Pred, template <class...> class R>
    struct append_if {
        template <typename A, class... xs>
        requires std::derived_from<Pred<A>, std::true_type>
        static push_front<R, A, xs...>::type const get() {
    
        }
        template <typename A, class... xs>
        requires std::derived_from<Pred<A>, std::false_type>
        static R<xs...> const get() {
    
        }
        template <size_t I, size_t S, class A, class... xs>
        requires (I == 0)
        static auto func() -> decltype(get<A, xs...>()) {
            //std::cout<<"I = 0 : "<<I<<std::endl;
    
        }
        template <size_t I, size_t S, class A, class... xs>
        requires (I != S-1 && I > 0)
        static constexpr auto const func() -> decltype(get<A, xs...>()) {
            //std::cout<<"I != S-1 : "<<I<<std::endl;
            //return func<I-1, S, decltype(get<A, seq>()), xs...>();
        }
        template <size_t I, size_t S, class A, class... xs>
        requires (I == S-1)
        static constexpr auto func() -> decltype(func<I-1, S, decltype(get<A, xs...>()), xs...>()) {
            //std::cout<<"I = S-1 : "<<I<<std::endl;
            //return func<I-1, S, decltype(get<A, list<>>()), xs...>();
        }
    };
    template<template <class> class Pred, typename C, template <class> class R>
    struct copy_if {
        template <class... xs>
        using f = decltype(append_if<C, Pred, R>::template func<sizeof...(xs)-1, sizeof...(xs), xs...>());
    };
    template<class T, template <class> class R>
    struct make_unique {
        template <typename A, class... xs>
        //requires std::derived_from<Pred<A>, std::true_type>
        static constexpr auto get() -> decltype(push_front<R,A, xs...>::type()){
            return push_front<R,A, xs...>::type();
        }
        /*template <typename A, class... xs>
        requires std::derived_from<Pred<A>, std::false_type>
        static constexpr auto get() -> decltype(std::tuple<xs...>()) {
            return std::tuple<A, xs...>();
        }*/
        template <size_t I=0, size_t... Ints>
        requires (I == std::tuple_size<T>())
        static constexpr auto func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints+I-1>(T())())...>()) {
            return get<decltype(std::get<Ints+I-1>(T())())...>();
    
        }
        template <size_t I=0, size_t... Ints>
        requires (I > 0 && I != std::tuple_size<T>())
        static constexpr auto const func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints+I-1>(T())())...>()) {
            return get<decltype(std::get<Ints+I-1>(T())())...>();
        }
        template <size_t I=0, size_t... Ints>
        requires (I == 0)
        static constexpr auto func(std::index_sequence<Ints...>) -> decltype(func<I+1/*, decltype(get<decltype(std::get<Ints>(T())())...>)*/>(std::make_index_sequence<std::tuple_size<T>()-I>())) {
            return func<I+1/*, decltype(get<decltype(std::get<Ints>(T())())...>)*/>(std::make_index_sequence<std::tuple_size<T>()-I>());
        }
    };
    template<class L, template <class> class R>
    struct unique {
        using type = typename L::type;
        using f = decltype(make_unique<type, R>::func(std::make_index_sequence<std::tuple_size<type>()-0>()));
    };
    int main(int argc, char* argv[])
    {
        using late_params_t
                  = unique<copy_if<is_placeholder,list<placeholder<3, int>, int, placeholder<2, int>,placeholder<1, int>,placeholder<0, int>>, list>
                    ::f<placeholder<3, int>, int, placeholder<2, int>,placeholder<1, int>,placeholder<0, int>>, LateParameters>::f;
        std::cout<<typeid(late_params_t).name()<<std::endl; return 0; }

    Pourquoi le compilateur n'arrive pas à déduire les types des éléments extrait du tuple ?

    -
    Edité par OmbreNoire 8 juin 2021 à 23:47:10

    • Partager sur Facebook
    • Partager sur Twitter
      9 juin 2021 à 0:05:06

      Je pensais que tu faisais du C++17, non ?

      Les concepts sont du C++20. Vérifie que c'est correctement supporté sur ton compilateur.

      A part quelques erreurs de syntaxe et les "placeholder<>" dans la fonction main() qui n'existent pas, le code compile sur clang.

      • Partager sur Facebook
      • Partager sur Twitter
        9 juin 2021 à 0:45:21

        gbdivers a écrit:

        Je pensais que tu faisais du C++17, non ?

        Les concepts sont du C++20. Vérifie que c'est correctement supporté sur ton compilateur.

        A part quelques erreurs de syntaxe et les "placeholder<>" dans la fonction main() qui n'existent pas, le code compile sur clang.


        Mon compilateur supporte le c++20 normalement c'est la dernière version de mingw-W64.

        Bizarre que chez moi ça ne compile pas!!!

        • Partager sur Facebook
        • Partager sur Twitter
          9 juin 2021 à 0:54:14

          Il y a des erreurs dans ton code. J'ai dû les corriger pour compiler.

          Et "placeholder" n'est pas défini, j'ai commenté le code de main.

          En tout cas, je n'ai pas d'erreur avec tuple.

          • Partager sur Facebook
          • Partager sur Twitter
            9 juin 2021 à 1:11:05

            gbdivers a écrit:

            Il y a des erreurs dans ton code. J'ai dû les corriger pour compiler.

            Et "placeholder" n'est pas défini, j'ai commenté le code de main.

            En tout cas, je n'ai pas d'erreur avec tuple.


            Je l'ai défini ailleur placeholder.

            Je vais essayer de compiler avec clang parce que j'ai d'autres problèmes avec mingw-W64 notamment faux résultats de calculs.

            En commentant le code du main ça compile.

            -
            Edité par OmbreNoire 9 juin 2021 à 1:12:51

            • Partager sur Facebook
            • Partager sur Twitter
              9 juin 2021 à 2:23:04

              > En commentant le code du main ça compile.

              Logique, vu qu'il n'y a aucune spécialisation nécessaire, ce qui résulte en ... à peu près rien de compilé x)

              • Partager sur Facebook
              • Partager sur Twitter

              Si vous ne trouvez plus rien, cherchez autre chose.

                9 juin 2021 à 12:05:30

                Bon j'ai laissé tombé, je ne parviens pas à faire un code qui compile avec mingw-W64 il n'arrive pas à déduire les types lorsque j'utilise la méta fonction dans le main. Je voulais tenter de le faire parce que le fichier mp.h ne compile pas avec visual studio 2019 et je voulais voir si ça plantait aussi avec visual studio, au pire je peux essayer mais sans l'implémentation pour les placeholders c'est à dire sans le fichier mp.h.

                • Partager sur Facebook
                • Partager sur Twitter
                  9 juin 2021 à 18:22:15

                  Salut,

                  Pourrais tu m'expliquer ce que tu souhaite faire avec le code
                  template <typename A>
                      requires std::derived_from<std::is_same<C, A>, std::true_type>
                      static constexpr std::true_type c () {
                          return std::true_type();
                      }

                  Car, je suis peut-être un peu fatigué après ma journée chargée, mais, à moins que je ne me trompe, std::derived_from permet de vérifier si un type (une classe) donné(e) est dérivé(e) d'une autre.

                  Et donc, tu veux t'assurer -- si je comprend bien ce code -- que le résultat de std::is_sama<A, C> soit bien dérivé de std::true_type; ce qui ne pourrait a priori arriver que si A et C sont des types identiques.

                  Heuu... n'as tu pas l'impression de faire finalement bien compliqué pour pas grand chose???

                  Je sais pas moi, mais je verrais bien plutôt quelque chose comme

                  template <typename U, typename V>
                  concept IsSame = std::is_same<U, V>::value == true;
                  template <typename U, typename V>
                  template <typename C>
                  struct contains {
                      template <typename A>
                      requires IsSame
                      static constexpr std::true_type c () {
                          return std::true_type();
                      }
                      template <typename A>
                      requires !IsSame
                      static constexpr std::false_type c () {
                          return std::false_type();
                      }
                      /* ... */

                  (le tout sans tenir compte du fait que tu chrerches peut-être les problèmes à renvoyer spécifiquement true_type et false_type ici )


                  • Partager sur Facebook
                  • Partager sur Twitter
                  Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                    9 juin 2021 à 19:22:44

                    Ok mais c'est pas ça le problème je pense et puis, de toute façon je n'ai plus le temps pour implémenter ça, il faut que j'avance sur mon projet de jeux, sinon, je ne sortirai jamais la bêta.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 juin 2021 à 9:12:41

                      J'ai tenté de compiler ce code mais il le compilateur ne peut pas déduire le type et j'ai d'autre erreurs (expression cannot be used as a function) que je ne comprend pas.

                      template<class T>
                      struct is_placeholder
                      : std::false_type
                      {};
                      
                      template<std::size_t I, class T>
                      struct is_placeholder<ph<I, T>>
                      : std::true_type
                      {};
                      template <template <class...> class L, class A, class... Args>
                      struct push_front {
                          using type = L<A, Args...>;
                      };
                      template<class T, template<class> class Pred, template <class...> class R>
                      struct append_if {
                          template <typename A, class D, class... xs, class = typename std::enable_if<Pred<A>::value>::type>
                          static constexpr auto get() -> decltype(push_front<R,A, xs...>::type()){
                              return push_front<R,A, xs...>::type();
                          }
                          template <typename A, class... xs>
                          static constexpr auto get() -> decltype(R<xs...>()) {
                              return R<xs...>();
                          }
                          template <size_t I=0, class... D,class...E, size_t... Ints, class = typename std::enable_if<I == std::tuple_size<T>()>>
                          static constexpr auto func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints>(T())())...>()) {
                              return get<decltype(std::get<Ints>(T())())...>();
                      
                          }
                          template <size_t I=0, class... D, size_t... Ints, class = typename std::enable_if<I != 0 && I != std::tuple_size<T>()>>
                          static constexpr auto const func(std::index_sequence<Ints...>) -> decltype(get<decltype(std::get<Ints>(T())())...>()) {
                              return get<decltype(std::get<Ints>(T())())...>();
                          }
                          template <size_t I=0, size_t... Ints>
                          static constexpr auto func(std::index_sequence<Ints...>) -> decltype(func<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>())) {
                              return func<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>());
                          }
                      };
                      template<template <class> class Pred, typename T, template <class> class R>
                      struct copy_if {
                          using f = decltype(append_if<T, Pred, R>::template func(std::make_index_sequence<std::tuple_size<T>()-0>()));
                      };
                      int main(int argc, char* argv[])
                      {
                          using late_params_t
                                    = copy_if<is_placeholder,std::tuple<int, ph<3, int>, ph<2, int>,ph<1, int>,ph<0, int>>, std::tuple>
                                      ::f;
                          std::cout<<typeid(late_params_t).name()<<std::endl;
                      
                          return 0;  }



                      -
                      Edité par OmbreNoire 11 juin 2021 à 9:16:06

                      • Partager sur Facebook
                      • Partager sur Twitter
                        11 juin 2021 à 10:49:52

                        Et ph, dans ton code, il correspond à quoi, exactement?

                        Car, pour que ton code puisse compiler avec is_placeholder valant true, il faudrait que ph corresponde à quelque chose comme

                        template <typename T>
                        struct ph{
                            using type = T;
                        };
                        template <size_t SIZE, typename T>
                        struct ph{
                            static size_t constexpr size = SIZE;
                            using size_type = size_t;
                            using type = T;
                        };

                        De cette manière, tu pourrais créer is_placeholder sous une forme proche de

                        template <typename T>
                        struct is_placeholder: false_type{
                           using value_type = typename ph<T>::type;
                        };
                        template <size_t SIZE, typename T>
                        struct is_placeholder: true_type{
                            using value_type = typename ph<SIZE, T>::type;
                            static size_t constexpr size = ph<SIZE, T>::size;
                        };

                        et la suite pourra alors être à l'avenant ;)

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                          11 juin 2021 à 11:43:02

                          Salut! Ah oui, j'ai oublier de spécifier ph, en fait ph c'est ça :

                          template<size_t I, class T>
                                  struct ph : 
                                  {
                                      
                                  };

                          EDIT : j'ai presque réussi grâce à ce lien : https://devblogs.microsoft.com/oldnewthing/20200624-00/?p=103902

                          C'est juste que il ne me rajoute pas le premier placeholder lorsqu'il n'y a aucun type défini avant lui c'est vraiment bizarre!!!

                          template <size_t SIZE, typename T>
                          struct placeholder {
                              static size_t constexpr size = SIZE;
                              using size_type = size_t;
                              using type = T;
                          };
                          template<class T>
                          struct is_placeholder
                          : std::false_type
                          {};
                          
                          template<std::size_t I, class T>
                          struct is_placeholder<placeholder<I, T>>
                          : std::true_type
                          {};
                          template <template <class...> class L, class A, class... Args>
                          struct push_front {
                              using type = L<A, Args...>;
                          };
                          template<std::size_t N, typename Seq> struct offset_sequence;
                          
                          template<std::size_t N, std::size_t... Ints>
                          struct offset_sequence<N, std::index_sequence<Ints...>>
                          {
                           using type = std::index_sequence<Ints + N...>;
                          };
                          template<std::size_t N, typename Seq>
                          using offset_sequence_t = typename offset_sequence<N, Seq>::type;
                          template <size_t O, size_t N, size_t... Ints>
                          std::index_sequence<Ints...> make_offset_sequence () {
                              return offset_sequence_t<O, std::make_index_sequence<N>>::type();
                          }
                          template<typename T, std::size_t... Ints>
                          auto select_tuple(std::index_sequence<Ints...>)
                          {
                           T tuple;
                           return std::make_tuple(
                              std::get<Ints>(std::forward<T>(tuple))...);
                          }
                          template<std::size_t N, typename T>
                          auto remove_Nth()
                          {
                            constexpr auto size = std::tuple_size_v<T>;
                            using first = std::make_index_sequence<N>;
                            using rest = offset_sequence_t<N+1,
                                          std::make_index_sequence<size-N-1>>;
                            return std::tuple_cat(
                              select_tuple<T>(first{}),
                              select_tuple<T>(rest{}));
                          }
                          template<template<class> class Pred, template <class...> class R>
                          struct append_if {
                              template <size_t I, class T, class... D, class = typename std::enable_if<Pred<decltype(std::get<I>(T()))>::value>::type>
                              static constexpr auto get() /*-> decltype(push_front<R,A, xs...>::type())*/{
                                  return T();
                              }
                              template <size_t I, class T, class = typename std::enable_if<!Pred<decltype(std::get<I>(T()))>::value>::type>
                              static constexpr auto get() /*-> decltype(R<xs...>())*/ {
                                  return remove_Nth<I, T>();
                              }
                              template <size_t I=0, class T, class... D, class = typename std::enable_if<(I == std::tuple_size<T>())>::type>
                              static constexpr auto f() /*-> decltype(get<decltype(std::get<Ints>(T())())...>())*/ {
                                  return get<I-1, T>();
                              }
                              template <size_t I=0, class T, class... D, class... E, class = typename std::enable_if<(I != 0 && I != std::tuple_size<T>())>::type>
                              static constexpr auto const f() /*-> decltype(get<decltype(std::get<Ints>(T())())...>())*/ {
                                  return get<I-1, T>();
                              }
                              template <size_t I=0, class T, class... D, class...E, class... F, class = typename std::enable_if<(I == 0)>::type>
                              static constexpr auto f() /*-> decltype(f<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>()))*/ {
                                  return f<I+1, T>();
                              }
                          };
                          template<template <class> class Pred, typename T, template <class> class R>
                          struct copy_if {
                              using f = decltype(append_if<Pred, R>::template f<0, T>());
                          };
                          
                          int main(int argc, char* argv[])
                          {
                              using late_params_t
                                        = copy_if<is_placeholder,std::tuple<placeholder<3, int>, float, placeholder<2, int>, int, placeholder<1, int>, char, placeholder<0, int>>, std::tuple>
                                          ::f;
                              std::cout<<typeid(late_params_t).name()<<std::endl;
                          
                              return 0;

                          La seule solution que j'ai trouvé c'est de rajouté un type bidon devant le premier placeholder et là, ça fonctionne!!!

                          using late_params_t
                                        = copy_if<is_placeholder,std::tuple<double, placeholder<3, int>, float, placeholder<2, int>, int, placeholder<1, int>, char, placeholder<0, int>>, std::tuple>
                                          ::f;
                              std::cout<<typeid(late_params_t).name()<<std::endl;
                          
                              return 0;

                          Maintenant il ne me reste plus qu'à faire la même chose pour, virer les placeholders qui sont identiques et les trier, c'est un bonne exercice pour manipuler les tuples!!!

                          EDIT 2 : j'ai trouvé l'erreur, ce code fonctionne!!!

                          template <size_t SIZE, typename T>
                          struct placeholder {
                              static size_t constexpr size = SIZE;
                              using size_type = size_t;
                              using type = T;
                          };
                          template<class T>
                          struct is_placeholder
                          : std::false_type
                          {};
                          
                          template<std::size_t I, class T>
                          struct is_placeholder<placeholder<I, T>>
                          : std::true_type
                          {};
                          template<std::size_t N, typename Seq> struct offset_sequence;
                          
                          template<std::size_t N, std::size_t... Ints>
                          struct offset_sequence<N, std::index_sequence<Ints...>>
                          {
                           using type = std::index_sequence<Ints + N...>;
                          };
                          template<std::size_t N, typename Seq>
                          using offset_sequence_t = typename offset_sequence<N, Seq>::type;
                          template <size_t O, size_t N, size_t... Ints>
                          std::index_sequence<Ints...> make_offset_sequence () {
                              return offset_sequence_t<O, std::make_index_sequence<N>>::type();
                          }
                          template<typename Seq1, typename Seq> struct cat_sequence;
                          template<std::size_t... Ints1, std::size_t... Ints2>
                          struct cat_sequence<std::index_sequence<Ints1...>,
                                              std::index_sequence<Ints2...>>
                          {
                           using type = std::index_sequence<Ints1..., Ints2...>;
                          };
                          template<typename Seq1, typename Seq2>
                          using cat_sequence_t = typename cat_sequence<Seq1, Seq2>::type;
                          template<typename T, std::size_t... Ints>
                          auto select_tuple(std::index_sequence<Ints...>)
                          {
                           T tuple;
                           return std::tuple<T>();
                          }
                          template<std::size_t N, typename T>
                          auto remove_Nth()
                          {
                            constexpr auto size = std::tuple_size_v<T>;
                            using first = std::make_index_sequence<N>;
                            using rest = offset_sequence_t<N+1,
                                          std::make_index_sequence<size-N-1>>;
                            using indices = cat_sequence_t<first, rest>;
                            return select_tuple<T>(indices{});
                          }
                          template<template<class> class Pred, template <class...> class R>
                          struct append_if {
                              template <size_t I, class T, class... D, class = typename std::enable_if<Pred<decltype(std::get<I>(T()))>::value>::type>
                              static constexpr auto get() /*-> decltype(push_front<R,A, xs...>::type())*/{
                                  return T();
                              }
                              template <size_t I, class T, class = typename std::enable_if<!Pred<decltype(std::get<I>(T()))>::value>::type>
                              static constexpr auto get() /*-> decltype(R<xs...>())*/ {
                                  return remove_Nth<I, T>();
                              }
                              template <size_t I=0, class T, class... D, class = typename std::enable_if<(I == std::tuple_size<T>())>::type>
                              static constexpr auto f() /*-> decltype(get<decltype(std::get<Ints>(T())())...>())*/ {
                                  return get<I-1, T>();
                              }
                              template <size_t I=0, class T, class... D, class... E, class = typename std::enable_if<(I != 0 && I != std::tuple_size<T>())>::type>
                              static constexpr auto const f() /*-> decltype(get<decltype(std::get<Ints>(T())())...>())*/ {
                                  return get<I-1, T>();
                              }
                              template <size_t I=0, class T, class... D, class...E, class... F, class = typename std::enable_if<(I == 0)>::type>
                              static constexpr auto f() /*-> decltype(f<I+1>(std::make_index_sequence<std::tuple_size<T>()-I>()))*/ {
                                  return f<I+1, T>();
                              }
                          };
                          template<template <class> class Pred, typename T, template <class> class R>
                          struct copy_if {
                              using f = decltype(append_if<Pred, R>::template f<0, T>());
                          };
                          int main(int argc, char* argv[])
                          {
                              using late_params_t
                                        = copy_if<is_placeholder,std::tuple<placeholder<3, int>, float, placeholder<2, int>, int, placeholder<1, int>, char, placeholder<0, int>>, std::tuple>::f;
                              std::cout<<typeid(late_params_t).name()<<std::endl;
                          
                              return 0;
                          }

                          Résolu!

                          Bon c'est moins rapide avec l'instanciation mais le code est moins salle que le fichier .hpp donc moins susceptible de planter.




                          -
                          Edité par OmbreNoire 11 juin 2021 à 16:41:02

                          • Partager sur Facebook
                          • Partager sur Twitter

                          Le compilateur ne peut pas déduire les types.

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown