Date: Thu, 9 Apr 2026 23:11:01 +0500
My answer to Mr.Bjorn: I didn't say that you did have book keeping, infact
that's the issue, like to copy a tuple elements in a variant and to make
sure that you can't change the type of that variant to anything afterwards,
you do need book keeping Information. Without a language level construct,
you can't optimize such Information without breaking ABI's, just like how
we needed flat maps, we need a language level construct.
On Thu, 9 Apr 2026, 10:52 pm Muneem, <itfllow123_at_[hidden]> wrote:
> In short answer: The programmers dosent know what book keeping actually
> works for that specific hardware.
>
> Detailed answer:
>
> 1. The programmers dosent know what book keeping actually works for that
> specific hardware. Programs compiled for extremely old legacy computer's
> don't have that much space to spare to get a cache Friendly design. Not to
> mention that there are many totally different computer that a programmer
> might not have even heard of, like the intel Xeon CPUs.
> 2. As shown in my example, I don't know if the N space overhead is better
> or should I opt to a recursive N-1 call to a base class that handles the
> rest while inheriting from that. Why? Because I don't know if the optimizer
> can optimize such recursion it out breaking ABI's or something, like I
> don't know that for every computer in the world and don't want to.
> 3. Dont rely on speed that is only there under "some circumstances".
> 4. This brings me back to writing Painful C code. Like the reason that I
> or anyone else moves from C to c++ is because C forces me to rewrite flat
> maps and what not. Even then my implementation is outperformed by the STL
> because I can't use inline assembly without spending a year learning each
> target architecture. A implementation like MSCV or Clang is.
>
> On Thu, 9 Apr 2026, 9:24 pm Sebastian Wittmeier via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
>> About book keeping information:
>>
>> 1) You can have book keeping data, which is set at compile-time and the
>> compiler chooses the optimal representation (e.g. templates)
>>
>> 2) Other book keeping data exists at runtime and is passed as parameters
>> or even stored in the object
>>
>> 2a) Of that some can under certain circumstances (no ABI boundary) be
>> removed again by the optimizer
>>
>>
>>
>>
>>
>>
>> -----Ursprüngliche Nachricht-----
>> *Von:* Muneem via Std-Proposals <std-proposals_at_[hidden]>
>> *Gesendet:* Do 09.04.2026 14:55
>> *Betreff:* Re: [std-proposals] Fwd: Extension to runtime polymorphism
>> proposed
>> *An:* std-proposals_at_[hidden];
>> *CC:* Muneem <itfllow123_at_[hidden]>;
>> That's the whole point, tuple dosent keep any book keeping data, it has
>> always been a fun little wierd variadic template struct inheriting from
>> itself, but you don't want that for book keeping Information, and you can't
>> change that without breaking ABI's. To truly optimize without breaking
>> ABI's you need newer mechanics, like you can't optimize a std::list without
>> introducing std::vector.
>> ****Some philosophical analogy(sorry if it's too abstract and
>> personal)****
>> About the Mr.herb, my answer is that languages change and they must, and
>> we should not allow a few people to force us to build vertically.
>> Personally, I have roots in Afghanistan and Soviets always tried to
>> completely eradicate villages because they saw them as horizontal
>> resistance that keeps on growing exponentially in every direction. The same
>> guys, loved, protected, and heavily developed Afghan urban centers and
>> infrustructure. At the end the horizontal resistance won. The point is that
>> if you have a language that's not willing to grow out of it's pre existing
>> philosophies someone will replace it. Look at C, C++ replaced C. Nothing
>> lives for ever unless it gives rebirth to something else, c++ has been
>> doing it for years, but is stopping now.The main reason for this proposal
>> was that you can't fix everything with metaprogramming techniques, like the
>> sky has a limit unlike what most say:
>> ***How my *container would feel like* ***:
>> #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<N, Head_t, Tail...> {
>> std::size_t tag;
>> union {
>> struct {
>> Head_t* reference;
>> } head;
>> Element_t<N - 1, Tail...> tail;
>> };
>>
>> inline Element_t(Head_t& a) : tag{N} {
>> head.reference = &a;
>> }
>>
>> template<typename T>
>> inline Element_t(T&& a) : tail{ std::forward<T>(a) } {
>> tag = tail.tag;
>> }
>>
>> 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>(std::forward<T>(a));
>> }
>> }
>>
>> 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 <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) : tag{0} {
>> head.reference = &a;
>> }
>>
>> template<typename Func_t, typename T>
>> inline void dispatch(T&& a) {
>> if (tag == 0) {
>> Func_t{}(*head.reference, std::forward<T>(a));
>> }
>> }
>> };
>>
>> template <std::size_t N, typename... _Types>
>> class heterogeneous_list;
>>
>> template <std::size_t N, typename Head_t, typename... Tail>
>> class heterogeneous_list<N, Head_t, Tail...> : public
>> heterogeneous_list<N - 1, 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 heterogeneous_list<N - 1, Tail...>::operator[](index);
>> } 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"};
>> }
>> }
>> };
>>
>>
>>
>>
>>
>> The main point is that decentralized features always win because each
>> focuses on one, right now, we are using metaprogramming for everything and
>> it's a mess! (Look above!!)
>>
>> On Wed, 8 Apr 2026, 9:52 pm Simon Schröder via Std-Proposals, <
>> std-proposals_at_[hidden]> wrote:
>>
>>
>>
>> > On Apr 8, 2026, at 9:47 AM, Muneem <itfllow123_at_[hidden]> wrote:
>> >
>> > int^ x = {1,2.5,”C++”}.select(2); This would throw a huge error at
>> compile time and is exactly why we need a new expression type T^. Not using
>> T^ would give too much freedom that could backfire as shown in the example.
>> In fact for T^, you cant even assign float^ to an int^.
>>
>> May bad, I wasn’t clear enough with my example. I do understand that with
>> index=2 the compiler should use the compile time version and return the
>> correct type. What my question actually is what would happen if the index
>> is a runtime index that happens to be 2. How would the code be compiled to
>> handle this case? What would happen to following source code lines that use
>> ‘x’? Or would you just throw an exception?
>>
>> Concerning reflection: We are not there yet with C++26. But, the ultimate
>> goal is to be able to generate arbitrary code. And we will be able to read
>> in entire functions, analyze them and then replace the function with a new
>> one generated with reflection. (With C++26 we can only analyze classes and
>> generate new ones based on this.) In my opinion, everything you say the
>> compiler should generate for your type, reflection will be able to generate
>> in one of the two next C++ versions. You should really learn about
>> reflection; maybe watch one of Herb Sutter’s talk from last year. You’d be
>> surprised what reflection can actually do right now.
>>
>> And you don’t give compilers enough credit which things they can plainly
>> see through and optimize. std::tuple does not have any bookkeeping data: It
>> just stores the elements of a heterogeneous list. The types stored inside
>> the tuple are part of the tuple’s type itself and thus part of the function
>> signature. You cannot store less data than this. There is no type possible
>> which is more efficient than std::tuple. Note that std::tuple is not at all
>> comparable to std::vector<std::variant>. Your proposed type sounds a lot
>> more like std::vector<std::variant>. Even if it is a new type, as long as
>> it is more like a vector of variants it will necessarily be slower than a
>> std::tuple because your new type would include some bookkeeping (and
>> std::tuple does not).
>>
>> I can assure your that std::tuple is already the most performant type
>> possible for your heterogeneous list (unless you want a runtime resizable
>> heterogeneous list—which is not necessary for your Turing virtual machine).
>> The only thing left is how to get elements out of the std::tuple at runtime
>> and what type should be used here.
>> --
>> Std-Proposals mailing list
>> 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
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>
that's the issue, like to copy a tuple elements in a variant and to make
sure that you can't change the type of that variant to anything afterwards,
you do need book keeping Information. Without a language level construct,
you can't optimize such Information without breaking ABI's, just like how
we needed flat maps, we need a language level construct.
On Thu, 9 Apr 2026, 10:52 pm Muneem, <itfllow123_at_[hidden]> wrote:
> In short answer: The programmers dosent know what book keeping actually
> works for that specific hardware.
>
> Detailed answer:
>
> 1. The programmers dosent know what book keeping actually works for that
> specific hardware. Programs compiled for extremely old legacy computer's
> don't have that much space to spare to get a cache Friendly design. Not to
> mention that there are many totally different computer that a programmer
> might not have even heard of, like the intel Xeon CPUs.
> 2. As shown in my example, I don't know if the N space overhead is better
> or should I opt to a recursive N-1 call to a base class that handles the
> rest while inheriting from that. Why? Because I don't know if the optimizer
> can optimize such recursion it out breaking ABI's or something, like I
> don't know that for every computer in the world and don't want to.
> 3. Dont rely on speed that is only there under "some circumstances".
> 4. This brings me back to writing Painful C code. Like the reason that I
> or anyone else moves from C to c++ is because C forces me to rewrite flat
> maps and what not. Even then my implementation is outperformed by the STL
> because I can't use inline assembly without spending a year learning each
> target architecture. A implementation like MSCV or Clang is.
>
> On Thu, 9 Apr 2026, 9:24 pm Sebastian Wittmeier via Std-Proposals, <
> std-proposals_at_[hidden]> wrote:
>
>> About book keeping information:
>>
>> 1) You can have book keeping data, which is set at compile-time and the
>> compiler chooses the optimal representation (e.g. templates)
>>
>> 2) Other book keeping data exists at runtime and is passed as parameters
>> or even stored in the object
>>
>> 2a) Of that some can under certain circumstances (no ABI boundary) be
>> removed again by the optimizer
>>
>>
>>
>>
>>
>>
>> -----Ursprüngliche Nachricht-----
>> *Von:* Muneem via Std-Proposals <std-proposals_at_[hidden]>
>> *Gesendet:* Do 09.04.2026 14:55
>> *Betreff:* Re: [std-proposals] Fwd: Extension to runtime polymorphism
>> proposed
>> *An:* std-proposals_at_[hidden];
>> *CC:* Muneem <itfllow123_at_[hidden]>;
>> That's the whole point, tuple dosent keep any book keeping data, it has
>> always been a fun little wierd variadic template struct inheriting from
>> itself, but you don't want that for book keeping Information, and you can't
>> change that without breaking ABI's. To truly optimize without breaking
>> ABI's you need newer mechanics, like you can't optimize a std::list without
>> introducing std::vector.
>> ****Some philosophical analogy(sorry if it's too abstract and
>> personal)****
>> About the Mr.herb, my answer is that languages change and they must, and
>> we should not allow a few people to force us to build vertically.
>> Personally, I have roots in Afghanistan and Soviets always tried to
>> completely eradicate villages because they saw them as horizontal
>> resistance that keeps on growing exponentially in every direction. The same
>> guys, loved, protected, and heavily developed Afghan urban centers and
>> infrustructure. At the end the horizontal resistance won. The point is that
>> if you have a language that's not willing to grow out of it's pre existing
>> philosophies someone will replace it. Look at C, C++ replaced C. Nothing
>> lives for ever unless it gives rebirth to something else, c++ has been
>> doing it for years, but is stopping now.The main reason for this proposal
>> was that you can't fix everything with metaprogramming techniques, like the
>> sky has a limit unlike what most say:
>> ***How my *container would feel like* ***:
>> #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<N, Head_t, Tail...> {
>> std::size_t tag;
>> union {
>> struct {
>> Head_t* reference;
>> } head;
>> Element_t<N - 1, Tail...> tail;
>> };
>>
>> inline Element_t(Head_t& a) : tag{N} {
>> head.reference = &a;
>> }
>>
>> template<typename T>
>> inline Element_t(T&& a) : tail{ std::forward<T>(a) } {
>> tag = tail.tag;
>> }
>>
>> 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>(std::forward<T>(a));
>> }
>> }
>>
>> 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 <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) : tag{0} {
>> head.reference = &a;
>> }
>>
>> template<typename Func_t, typename T>
>> inline void dispatch(T&& a) {
>> if (tag == 0) {
>> Func_t{}(*head.reference, std::forward<T>(a));
>> }
>> }
>> };
>>
>> template <std::size_t N, typename... _Types>
>> class heterogeneous_list;
>>
>> template <std::size_t N, typename Head_t, typename... Tail>
>> class heterogeneous_list<N, Head_t, Tail...> : public
>> heterogeneous_list<N - 1, 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 heterogeneous_list<N - 1, Tail...>::operator[](index);
>> } 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"};
>> }
>> }
>> };
>>
>>
>>
>>
>>
>> The main point is that decentralized features always win because each
>> focuses on one, right now, we are using metaprogramming for everything and
>> it's a mess! (Look above!!)
>>
>> On Wed, 8 Apr 2026, 9:52 pm Simon Schröder via Std-Proposals, <
>> std-proposals_at_[hidden]> wrote:
>>
>>
>>
>> > On Apr 8, 2026, at 9:47 AM, Muneem <itfllow123_at_[hidden]> wrote:
>> >
>> > int^ x = {1,2.5,”C++”}.select(2); This would throw a huge error at
>> compile time and is exactly why we need a new expression type T^. Not using
>> T^ would give too much freedom that could backfire as shown in the example.
>> In fact for T^, you cant even assign float^ to an int^.
>>
>> May bad, I wasn’t clear enough with my example. I do understand that with
>> index=2 the compiler should use the compile time version and return the
>> correct type. What my question actually is what would happen if the index
>> is a runtime index that happens to be 2. How would the code be compiled to
>> handle this case? What would happen to following source code lines that use
>> ‘x’? Or would you just throw an exception?
>>
>> Concerning reflection: We are not there yet with C++26. But, the ultimate
>> goal is to be able to generate arbitrary code. And we will be able to read
>> in entire functions, analyze them and then replace the function with a new
>> one generated with reflection. (With C++26 we can only analyze classes and
>> generate new ones based on this.) In my opinion, everything you say the
>> compiler should generate for your type, reflection will be able to generate
>> in one of the two next C++ versions. You should really learn about
>> reflection; maybe watch one of Herb Sutter’s talk from last year. You’d be
>> surprised what reflection can actually do right now.
>>
>> And you don’t give compilers enough credit which things they can plainly
>> see through and optimize. std::tuple does not have any bookkeeping data: It
>> just stores the elements of a heterogeneous list. The types stored inside
>> the tuple are part of the tuple’s type itself and thus part of the function
>> signature. You cannot store less data than this. There is no type possible
>> which is more efficient than std::tuple. Note that std::tuple is not at all
>> comparable to std::vector<std::variant>. Your proposed type sounds a lot
>> more like std::vector<std::variant>. Even if it is a new type, as long as
>> it is more like a vector of variants it will necessarily be slower than a
>> std::tuple because your new type would include some bookkeeping (and
>> std::tuple does not).
>>
>> I can assure your that std::tuple is already the most performant type
>> possible for your heterogeneous list (unless you want a runtime resizable
>> heterogeneous list—which is not necessary for your Turing virtual machine).
>> The only thing left is how to get elements out of the std::tuple at runtime
>> and what type should be used here.
>> --
>> Std-Proposals mailing list
>> 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
>>
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden]
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>>
>
Received on 2026-04-09 18:11:16
