Date: Thu, 9 Apr 2026 21:58:56 +0200
Within the same standard library ABI (= architecture ABI + standard library version) you typically have the same class layout.
So you cannot just have a different class layout for each processor out there.
Your argument (or one of your arguments) is that your new feature allows for better performance, and having less book keeping overhead.
How should we understand that argument, if you don't even give an idea how the class layout should or could look like?
If the class layout is the same as existing types, then the question is, why it should be faster at all.
Important aspects are how short the class layout is (object size) and how easy it is to access for typical operations (number of accesses needed, memory indirections, and if you want cache lines). You don't have to give a definition for all possible layouts, just an example for understanding the difference. (You don't actually *have* to do anything, but it would help the discussion.)
Existing building blocks have very simple class layouts:
std::tuple is one element after the other, with some padding for correct alignment. (in some standard libraries in reverse order of elements)
std::variant is like a union, each possible value type stored in the same buffer together with an index, signifying which type it has.
Why would your class layouts be so complicated that they cannot be described or reasoned about?
We (or at least me) have to understand, where the performance speedup is coming from. Not from some philosophical musings, but from a direct description.
-----Ursprüngliche Nachricht-----
Von:Muneem via Std-Proposals <std-proposals_at_[hidden]>
Gesendet:Do 09.04.2026 19:53
Betreff:Re: [std-proposals] Fwd: Extension to runtime polymorphism proposed
An:std-proposals_at_[hidden];
CC:Muneem <itfllow123_at_[hidden]>;
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] <mailto: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] <mailto: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] <mailto:std-proposals_at_[hidden]> ;
CC:Muneem <itfllow123_at_[hidden] <mailto: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] <mailto:std-proposals_at_[hidden]> > wrote:
> On Apr 8, 2026, at 9:47 AM, Muneem <itfllow123_at_[hidden] <mailto: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] <mailto:Std-Proposals_at_[hidden]>
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
-- 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] <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-09 20:00:21
