C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Fwd: Extension to runtime polymorphism proposed

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Fri, 10 Apr 2026 09:53:25 +0200
You say, it will confuse the user. You mean the one using the user using the feature in main?   int main(){     heterogeneous_list<1, int, float> list;     auto element= list[1];     return 0; }   Seems quite easy to understand. (I would just question, what the 1 as first parameter of heterogeneous_list is doing.)     Or do you mean the one creating the library solution? That often are the implementers or very experienced developers. And such code has to be written only once. Perhaps it can be done in an easier to read fashion.   -----Ursprüngliche Nachricht----- Von:Muneem via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Fr 10.04.2026 08:22 Betreff:Re: [std-proposals] Fwd: Extension to runtime polymorphism proposed An:std-proposals_at_[hidden]; CC:Muneem <itfllow123_at_[hidden]>; The prove that I have is the fact that it will confuse any user to use any two of the codes below (or many other possible solutions and even then he technically can't outperform the language): (The first example is the same example as I added previouslt but with assignment operators and removed checks on the last type union inside element_t): #include <type_traits> #include <string> #include <utility>  struct false_t {}; struct true_t {};  template<typename T, typename... Tail> struct Is_t_in_set;  template<typename T, typename Head_t, typename... Tail> struct Is_t_in_set<T, Head_t, Tail...> {     using boolean = std::conditional_t<         std::is_same_v<T, Head_t>,         true_t,         typename Is_t_in_set<T, Tail...>::boolean     >; };  template<typename T, typename Head_t> struct Is_t_in_set<T, Head_t> {     using boolean = std::conditional_t<         std::is_same_v<T, Head_t>, true_t, false_t     >; };  struct empty_t {};  template<typename T> struct Alias_type {     using Type = T; };  template<typename T> using Alias_type_t = typename Alias_type<T>::Type;  template<typename... Args> struct N_type_unique_set;  template<typename Head_t, typename... Tail>  struct N_type_unique_set<Head_t, Tail...>     : std::conditional_t<         std::is_same_v<typename Is_t_in_set<Head_t, Tail...>::boolean, true_t>,          empty_t,          Alias_type<Head_t>     >, N_type_unique_set<Tail...>  {};  template<typename Head_t>  struct N_type_unique_set<Head_t> : Alias_type<Head_t> {};  template <std::size_t N, typename... _Types> struct Element_t; template <std::size_t N, typename Head_t, typename... Tail> struct Element_t_impl; template <std::size_t N, typename Head_t, typename... Tail> struct Element_t<N, Head_t, Tail...> {     std::size_t tag;     union {         struct {             Head_t* reference;         } head;         Element_t_impl<N - 1, Tail...> tail;     };      inline Element_t(Head_t& a) : tag{N} {          head.reference = &a;      }      template<typename T>     inline Element_t(T&& a) : tail{&tag, std::forward<T>(a) } {               }      template<typename Func_t, typename T>     inline void dispatch(T&& a) {         if (tag == N) {             Func_t{}(*head.reference, std::forward<T>(a));         } else {             tail.template dispatch<Func_t>(tag, std::forward<T>(a));         }     }          template<typename T>     inline T& operator=(T&& a) {        return tail. template copy(std::forward(a), tag);     }     inline Head_t& operator=(Head_t& a) {         if (tag == N) {             *head.reference = a;             return *head.reference;         } else {             throw std::string{"Assignment type mismatch"};         }     }      inline Head_t& operator=(Head_t&& a) {         if (tag == N) {             *head.reference = std::move(a);             return *head.reference;         } else {             throw std::string{"Assignment type mismatch"};         }     } }; template <std::size_t N, typename Head_t, typename... Tail> struct Element_t_impl {          union {         struct {             Head_t* reference;         } head;         Element_t_impl<N - 1, Tail...> tail;     };      inline Element_t_impl(std::size_t* tag,Head_t& a) {          head.reference = &a;          *tag=N;     }      template<typename T>     inline Element_t_impl(std::size_t* tag,T&& a) : tail{ tag, std::forward<T>(a) } {               }      template<typename Func_t, typename T>     inline void dispatch(const std::size_t tag, T&& a) {         if (tag == N) {             Func_t{}(*head.reference, std::forward<T>(a));         } else {             tail.template dispatch<Func_t>(tag, std::forward<T>(a));         }     } template<typename T>     inline T& copy(T&& a, const std::size_t tag) {        return tail. template copy(std::forward(a), tag);     }     inline Head_t& copy(Head_t& a, const std::size_t& tag) {         if (tag == N) {             *head.reference = a;             return *head.reference;         } else {             throw std::string{"Assignment type mismatch"};         }     }      inline Head_t& copy(Head_t&& a, const std::size_t tag) {         if (tag == N) {             *head.reference = std::move(a);             return *head.reference;         } else {             throw std::string{"Assignment type mismatch"};         }     } }; template <typename Head_t> struct Element_t<0, Head_t> {     std::size_t tag;     union {         struct {             Head_t* reference;         } head;     };      inline Element_t(Head_t& a) {          head.reference = &a;      }    inline Head_t& operator=(Head_t& a) {             *head.reference = a;             return *head.reference;             }      inline Head_t& operator=(Head_t&& a) {                        *head.reference = std::move(a);       return *head.reference;  }                  template<typename Func_t, typename T>     inline void dispatch(T&& a) {                      Func_t{}(*head.reference, std::forward<T>(a));              } };  template <typename Head_t> struct Element_t_impl<0, Head_t> {      union {         struct {             Head_t* reference;         } head;     };      inline Element_t_impl(std::size_t* tag, Head_t& a) {          head.reference = &a;         *tag= 0;     }    inline Head_t& copy(Head_t& a, std::size_t* tag) {             *head.reference = a;             return *head.reference;             }      inline Head_t& copy(Head_t&& a, const std::size_t tag) {                        *head.reference = std::move(a);       return *head.reference;  }                  template<typename Func_t, typename T>     inline void dispatch(std::size_t tag, T&& a) {                      Func_t{}(*head.reference, std::forward<T>(a));              } };  template <std::size_t N, typename... _Types> class heterogeneous_list; template <std::size_t N, typename type_set, typename... Tail> class heterogeneous_list_impl;  template <std::size_t N, typename Head_t, typename... Tail> class heterogeneous_list<N, Head_t, Tail...> : public heterogeneous_list_impl<N - 1,Element_t<N, Head_t, Tail...>,Tail...> {     Head_t Element; public:     using type_set = Element_t<N, Head_t, Tail...>;      type_set operator[](std::size_t index) {         if (index == N) {             return type_set(Element);         } else if constexpr (N > 0) {             return this->heterogeneous_list_impl<N - 1, type_set, Tail...>::operator[](index);         } else {             throw std::string{"out of bound access"};         }     } }; template <std::size_t N, typename type_set, typename Head_t, typename... Tail> class heterogeneous_list_impl<N, type_set, Head_t, Tail...> : public heterogeneous_list_impl<N - 1, type_set, Tail...> {     Head_t Element; public:      type_set operator[](std::size_t index) {         if (index == N) {             return type_set(Element);         } else if constexpr (N > 0) {             return this->heterogeneous_list_impl<N - 1, type_set,Tail...>::operator[](index);         } else {             throw std::string{"out of bound access"};         }     } }; template <typename type_set,typename Head_t> class heterogeneous_list_impl<0, type_set, Head_t> {     Head_t Element; public:          type_set operator[](std::size_t index) {         if (index == 0) {             return type_set(Element);         } else {             throw std::string{"out of bound access"};         }     } }; template <typename Head_t> class heterogeneous_list<0, Head_t> {     Head_t Element; public:     using type_set = Element_t<0, Head_t>;      type_set operator[](std::size_t index) {         if (index == 0) {             return type_set(Element);         } else {             throw std::string{"out of bound access"};         }     } }; int main(){     heterogeneous_list<1, int, float> list;     auto element= list[1];          return 0;        }  (Second one is without the linear N space complexity at the cost of having to pass tag/pointer to tag at runtime down the function call stack):   On Fri, 10 Apr 2026, 9:43 am Thiago Macieira via Std-Proposals, <std-proposals_at_[hidden] <mailto:std-proposals_at_[hidden]> > wrote: On Thursday, 9 April 2026 19:44:06 Pacific Daylight Time Muneem via Std- Proposals wrote: > All I am trying to say is that the implementation can do a better job at > knowing what to put in every single heterogeneous list element and in the > list as a whole. What proof do you have that it can? And how often do we need this intelligence? -- Thiago Macieira - thiago (AT) macieira.info <http://macieira.info> - thiago (AT) kde.org <http://kde.org>   Principal Engineer - Intel Data Center - Platform & Sys. Eng. -- Std-Proposals mailing list Std-Proposals_at_[hidden] <mailto:Std-Proposals_at_[hidden]> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2026-04-10 07:54:41