Date: Mon, 6 Apr 2026 03:44:00 +0500
Thanks for your feedback ❤️❤️❤️🙂
here is a way to make this type safe, which is unless the index is
constexpr, the return value is an object like std::variant. Your
abstraction is as I said fragile:
1.slicing even if you provide a virtual clone function, so my technique is
more type safe.
2.By gurrentied optimizations, I meant, the (subscript) operation is to be
completely inlined if the index is constexpr. This would again help someone
avoid having two define two functions, one constexpr and one runtime
polymorphic (virtual).
3. You can't pass storage[index] (in your example) to a function, expecting
the right overload to be called(in your example that function would have
different overloads for different "flavors"), which leads to all functions
possible be virtual members, and for operators or functions meant to return
a copy *this, we still have an issue of slicing; virtual members are
incomplete.
4.the user can't handle storage[index] in overloads, for example, there
might be a overload accepting storage&, but there can't be an overload
accepting storage& used for runtime polymorphism. This is an issue because
we are mixing references with polymorphism.
5. How is it not type safe? How are virtual clone functions more type safe?
On Mon, 6 Apr 2026, 3:29 am Steve Weinrich via Std-Proposals, <
std-proposals_at_[hidden]> wrote:
> Hi Muneem,
>
> Yes, I forget the closing ]...sorry.
>
> I believe that you keep missing an important point. What I have proposed
> is an abstraction. All of your points keep breaking the abstraction.
>
> Guaranteed optimization - perhaps you mean Guaranteed performance? If so,
> Storage can easily guarantee performance. For any given operation it is
> the simply the worst of all the "flavors."
>
> The user should not know or care about the exact implementation of
> Storage. They simply follow the interface. They do not know or care which
> container within Storage is being used.
>
> As I previously stated, you are fixated on a mechanism that will return a
> different type based on some criteria. IMHO, there is no way to make that
> type-safe.
>
> Cheers,
> Steve
>
>
> On Sun, Apr 5, 2026, 16:08 Muneem via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> After answering Mr.thiago, I forgot to answer Mr.steve, so my answer is:
>> >I have tried unsuccessfully to get Muneem to move from theoretical
>> concepts
>> into actual C++ code. I have shown a standard solution to his "storage"
>> problem (copied below), but so far he has been unwilling to work with
>> that.
>>
>> >He seems to be fixated on a container of some type that returns
>> references
>> to different type of containers. For the life of me, I can't figure out
>> why
>> this would be needed or how to make it type-safe!
>>
>> ///////////////////////////////////
>>
>> >A "standard" solution to storing the same type in different containers
>> based
>> on a run-time discrimination:
>>
>>
>> >class Storage
>> {
>> public:
>> class Data {// TBD };
>> class Key {// TBD};
>>
>> inline void put (const Key & key, const Data & data) {
>> storage[discriminator(data).put(key, data); }
>>
>> Data get (const Key &) const { return
>> storage[discriminator(data).put(key); }
>>
>>
>> private:
>> int discriminator (const Data &) { // do something}
>>
>> class Impl
>> {
>> public:
>> virtual void put (const Key &, const Data &) = 0;
>> virtual Data get (const Key &) const = 0;
>> };
>>
>> class FlavorOne : public Impl
>> {
>> private:
>> void put (const Key &, const Data &) override {// do something}
>> Data get (const Key &) const override {//do something}
>>
>> std::vector<Data> data;
>> };
>>
>> FlavorOne flavorOne;
>>
>> class FlavorTwo : public Impl
>> {
>> private:
>> void put (const Key &, const Data &) override {// do something}
>> Data get (const Key &) const override {//do something}
>>
>> std::list<Data> data;
>> };
>>
>> FlavorTwo flavorTwo;
>>
>> class FlavorThree : public Impl
>> {
>> private:
>> void put (const Data &) override {// do something}
>> Data get () const override {//do something}
>>
>> Std::deque<Data> data;
>> };
>>
>> FlavorThree flavorThree;
>>
>> std::array<Storage &, 3> storage(flavorOne, flavorTwo, flavorThree);
>> };
>>
>> Storage storage;
>>
>> To store some data: storage.put(data);
>> //I think you meant storage[discriminator(data)] but forgot ], but that's
>> fine, just wanted to make sure, I interprete your code right.
>>
>> ****Answer****
>> 1.I am really sorry for the confusion, I was trying to show Mr.Simon on
>> how to implement this (possible).
>> ******Proposed solution******
>> {List<int>, deque<int>, vector<int>}selector{int}
>> std::variant<List<int>&, deque<int>&, vector<int>&>
>> Destination = selector(runtime_value);
>> Or
>> List<int> a = selector(0); it would be an error if it wasent 0 and if the
>> index was not constexpr
>> (Unlike array of variants or in your case, an array of flavors, you can
>> copy and move in a type safe manner (gurrentied error if the index is
>> wrong)). Where as if your case, to move/copy a flavor out, you need a
>> virtual function like clone() that again leads to issues of slicing in case
>> the user does a mistake.
>>
>>
>>
>> **The point** is that with clearer rules, the user can reason well, and
>> even provide overloads based of the reasoning that he developed:
>> https://lists.isocpp.org/std-proposals/2026/04/17639.php
>> Not only that but you don't have to provide code for each get and push
>> member, but instead rely on the member ones in list, deque, and vector,
>> which can also lead to better inlining and less verbose code( I guess you
>> guys don't care about that, so sorry for mentioning it again) .
>>
>>
>>
>> ***Let's see what I thing is wrong with the current solution*****:
>> 2. No gurrentied optimizations:
>> (Refer to the potential gurrenties part):
>> https://lists.isocpp.org/std-proposals/2026/04/17639.php
>> 3. The current solution doesn't let the user pass storage to a function
>> and expect the function to know that the user is trying to implement this
>> pattern. That's the main goal of my new construct that users can handle
>> this pattern by new overrides. Like there can't be overloads that can see
>> that any value T is in std::array<Storage &, 3> storage and handles that.
>> This is an issue:
>> 1. You can't move/copy the container out of storage because it even if it
>> provides virtual copy/move assignment operators, the risk if undefined
>> behaviour still exist.
>> 2. Even if you know the container you want, ie, with a constexpr index,
>> c++ is not guaranteed to optimize the polymorphism away. Which means that
>> to be safe, some users provide two overloads, one for constexpr and another
>> for non constexpr.
>>
>>
>>
>> On Sun, 5 Apr 2026, 10:49 pm Steve Weinrich via Std-Proposals, <
>> std-proposals_at_[hidden]> wrote:
>>
>>> I have tried unsuccessfully to get Muneem to move from theoretical
>>> concepts
>>> into actual C++ code. I have shown a standard solution to his "storage"
>>> problem (copied below), but so far he has been unwilling to work with
>>> that.
>>>
>>> He seems to be fixated on a container of some type that returns
>>> references
>>> to different type of containers. For the life of me, I can't figure out
>>> why
>>> this would be needed or how to make it type-safe!
>>>
>>> ///////////////////////////////////
>>>
>>> A "standard" solution to storing the same type in different containers
>>> based
>>> on a run-time discrimination:
>>>
>>> class Storage
>>> {
>>> public:
>>> class Data {// TBD };
>>> class Key {// TBD};
>>>
>>> inline void put (const Key & key, const Data & data) {
>>> storage[discriminator(data).put(key, data); }
>>> Data get (const Key &) const { return
>>> storage[discriminator(data).put(key); }
>>>
>>> private:
>>> int discriminator (const Data &) { // do something}
>>>
>>> class Impl
>>> {
>>> public:
>>> virtual void put (const Key &, const Data &) = 0;
>>> virtual Data get (const Key &) const = 0;
>>> };
>>>
>>> class FlavorOne : public Impl
>>> {
>>> private:
>>> void put (const Key &, const Data &) override {// do something}
>>> Data get (const Key &) const override {//do something}
>>>
>>> std::vector<Data> data;
>>> };
>>>
>>> FlavorOne flavorOne;
>>>
>>> class FlavorTwo : public Impl
>>> {
>>> private:
>>> void put (const Key &, const Data &) override {// do something}
>>> Data get (const Key &) const override {//do something}
>>>
>>> std::list<Data> data;
>>> };
>>>
>>> FlavorTwo flavorTwo;
>>>
>>> class FlavorThree : public Impl
>>> {
>>> private:
>>> void put (const Data &) override {// do something}
>>> Data get () const override {//do something}
>>>
>>> Std::deque<Data> data;
>>> };
>>>
>>> FlavorThree flavorThree;
>>>
>>> std::array<Storage &, 3> storage(flavorOne, flavorTwo, flavorThree);
>>> };
>>>
>>> Storage storage;
>>>
>>> To store some data: storage.put(data);
>>>
>>> -----Original Message-----
>>> From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf
>>> Of
>>> Thiago Macieira via Std-Proposals
>>> Sent: Sunday, April 5, 2026 10:04 AM
>>> To: std-proposals_at_[hidden]
>>> Cc: Thiago Macieira <thiago_at_[hidden]>
>>> Subject: Re: [std-proposals] Fwd: Extension to runtime polymorphism
>>> proposed
>>>
>>> On Saturday, 4 April 2026 23:57:02 Pacific Daylight Time Simon Schröder
>>> via
>>> Std-Proposals wrote:
>>> > Also, rvalues (if I’m not mistaken) go down to the IR and don’t
>>> > optimize on the level of the AST. If your optimizations can only be
>>> > done on the AST, this is certainly a totally different thing.
>>> >
>>> > Don’t just use “guaranteed semantics” as a buzz word, but actually
>>> > describe what you want to guarantee
>>>
>>> Muneem might be misusing "AST optimisation" term. If we put together the
>>> two
>>> above, what he may be proposing is like what rvalue references enabled:
>>> distinct functions that may be able to do more/different things than what
>>> existed before. That would be a difference in the AST, because it would
>>> be a
>>> different program altogether.
>>>
>>> However:
>>> a) I don't know if that's the case. There's no syntax proposed.
>>>
>>> b) even what little I understand doesn't match the problem in question of
>>> replacing a switch
>>>
>>> c) I don't buy that this is worth it, because without a clear
>>> explanation of
>>> where this solution would be used, it's impossible to judge its value
>>>
>>> The adding of even more seemingly unrelated things into the discussion,
>>> like
>>> virtual functions, does not help understanding what the problem is.
>>> Making
>>> imprecise statements that can be easily refuted only muddies the problem
>>> further.
>>>
>>> --
>>> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
>>> Principal Engineer - Intel Data Center - Platform & Sys. Eng.
>>>
>>> --
>>> 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
>
here is a way to make this type safe, which is unless the index is
constexpr, the return value is an object like std::variant. Your
abstraction is as I said fragile:
1.slicing even if you provide a virtual clone function, so my technique is
more type safe.
2.By gurrentied optimizations, I meant, the (subscript) operation is to be
completely inlined if the index is constexpr. This would again help someone
avoid having two define two functions, one constexpr and one runtime
polymorphic (virtual).
3. You can't pass storage[index] (in your example) to a function, expecting
the right overload to be called(in your example that function would have
different overloads for different "flavors"), which leads to all functions
possible be virtual members, and for operators or functions meant to return
a copy *this, we still have an issue of slicing; virtual members are
incomplete.
4.the user can't handle storage[index] in overloads, for example, there
might be a overload accepting storage&, but there can't be an overload
accepting storage& used for runtime polymorphism. This is an issue because
we are mixing references with polymorphism.
5. How is it not type safe? How are virtual clone functions more type safe?
On Mon, 6 Apr 2026, 3:29 am Steve Weinrich via Std-Proposals, <
std-proposals_at_[hidden]> wrote:
> Hi Muneem,
>
> Yes, I forget the closing ]...sorry.
>
> I believe that you keep missing an important point. What I have proposed
> is an abstraction. All of your points keep breaking the abstraction.
>
> Guaranteed optimization - perhaps you mean Guaranteed performance? If so,
> Storage can easily guarantee performance. For any given operation it is
> the simply the worst of all the "flavors."
>
> The user should not know or care about the exact implementation of
> Storage. They simply follow the interface. They do not know or care which
> container within Storage is being used.
>
> As I previously stated, you are fixated on a mechanism that will return a
> different type based on some criteria. IMHO, there is no way to make that
> type-safe.
>
> Cheers,
> Steve
>
>
> On Sun, Apr 5, 2026, 16:08 Muneem via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> After answering Mr.thiago, I forgot to answer Mr.steve, so my answer is:
>> >I have tried unsuccessfully to get Muneem to move from theoretical
>> concepts
>> into actual C++ code. I have shown a standard solution to his "storage"
>> problem (copied below), but so far he has been unwilling to work with
>> that.
>>
>> >He seems to be fixated on a container of some type that returns
>> references
>> to different type of containers. For the life of me, I can't figure out
>> why
>> this would be needed or how to make it type-safe!
>>
>> ///////////////////////////////////
>>
>> >A "standard" solution to storing the same type in different containers
>> based
>> on a run-time discrimination:
>>
>>
>> >class Storage
>> {
>> public:
>> class Data {// TBD };
>> class Key {// TBD};
>>
>> inline void put (const Key & key, const Data & data) {
>> storage[discriminator(data).put(key, data); }
>>
>> Data get (const Key &) const { return
>> storage[discriminator(data).put(key); }
>>
>>
>> private:
>> int discriminator (const Data &) { // do something}
>>
>> class Impl
>> {
>> public:
>> virtual void put (const Key &, const Data &) = 0;
>> virtual Data get (const Key &) const = 0;
>> };
>>
>> class FlavorOne : public Impl
>> {
>> private:
>> void put (const Key &, const Data &) override {// do something}
>> Data get (const Key &) const override {//do something}
>>
>> std::vector<Data> data;
>> };
>>
>> FlavorOne flavorOne;
>>
>> class FlavorTwo : public Impl
>> {
>> private:
>> void put (const Key &, const Data &) override {// do something}
>> Data get (const Key &) const override {//do something}
>>
>> std::list<Data> data;
>> };
>>
>> FlavorTwo flavorTwo;
>>
>> class FlavorThree : public Impl
>> {
>> private:
>> void put (const Data &) override {// do something}
>> Data get () const override {//do something}
>>
>> Std::deque<Data> data;
>> };
>>
>> FlavorThree flavorThree;
>>
>> std::array<Storage &, 3> storage(flavorOne, flavorTwo, flavorThree);
>> };
>>
>> Storage storage;
>>
>> To store some data: storage.put(data);
>> //I think you meant storage[discriminator(data)] but forgot ], but that's
>> fine, just wanted to make sure, I interprete your code right.
>>
>> ****Answer****
>> 1.I am really sorry for the confusion, I was trying to show Mr.Simon on
>> how to implement this (possible).
>> ******Proposed solution******
>> {List<int>, deque<int>, vector<int>}selector{int}
>> std::variant<List<int>&, deque<int>&, vector<int>&>
>> Destination = selector(runtime_value);
>> Or
>> List<int> a = selector(0); it would be an error if it wasent 0 and if the
>> index was not constexpr
>> (Unlike array of variants or in your case, an array of flavors, you can
>> copy and move in a type safe manner (gurrentied error if the index is
>> wrong)). Where as if your case, to move/copy a flavor out, you need a
>> virtual function like clone() that again leads to issues of slicing in case
>> the user does a mistake.
>>
>>
>>
>> **The point** is that with clearer rules, the user can reason well, and
>> even provide overloads based of the reasoning that he developed:
>> https://lists.isocpp.org/std-proposals/2026/04/17639.php
>> Not only that but you don't have to provide code for each get and push
>> member, but instead rely on the member ones in list, deque, and vector,
>> which can also lead to better inlining and less verbose code( I guess you
>> guys don't care about that, so sorry for mentioning it again) .
>>
>>
>>
>> ***Let's see what I thing is wrong with the current solution*****:
>> 2. No gurrentied optimizations:
>> (Refer to the potential gurrenties part):
>> https://lists.isocpp.org/std-proposals/2026/04/17639.php
>> 3. The current solution doesn't let the user pass storage to a function
>> and expect the function to know that the user is trying to implement this
>> pattern. That's the main goal of my new construct that users can handle
>> this pattern by new overrides. Like there can't be overloads that can see
>> that any value T is in std::array<Storage &, 3> storage and handles that.
>> This is an issue:
>> 1. You can't move/copy the container out of storage because it even if it
>> provides virtual copy/move assignment operators, the risk if undefined
>> behaviour still exist.
>> 2. Even if you know the container you want, ie, with a constexpr index,
>> c++ is not guaranteed to optimize the polymorphism away. Which means that
>> to be safe, some users provide two overloads, one for constexpr and another
>> for non constexpr.
>>
>>
>>
>> On Sun, 5 Apr 2026, 10:49 pm Steve Weinrich via Std-Proposals, <
>> std-proposals_at_[hidden]> wrote:
>>
>>> I have tried unsuccessfully to get Muneem to move from theoretical
>>> concepts
>>> into actual C++ code. I have shown a standard solution to his "storage"
>>> problem (copied below), but so far he has been unwilling to work with
>>> that.
>>>
>>> He seems to be fixated on a container of some type that returns
>>> references
>>> to different type of containers. For the life of me, I can't figure out
>>> why
>>> this would be needed or how to make it type-safe!
>>>
>>> ///////////////////////////////////
>>>
>>> A "standard" solution to storing the same type in different containers
>>> based
>>> on a run-time discrimination:
>>>
>>> class Storage
>>> {
>>> public:
>>> class Data {// TBD };
>>> class Key {// TBD};
>>>
>>> inline void put (const Key & key, const Data & data) {
>>> storage[discriminator(data).put(key, data); }
>>> Data get (const Key &) const { return
>>> storage[discriminator(data).put(key); }
>>>
>>> private:
>>> int discriminator (const Data &) { // do something}
>>>
>>> class Impl
>>> {
>>> public:
>>> virtual void put (const Key &, const Data &) = 0;
>>> virtual Data get (const Key &) const = 0;
>>> };
>>>
>>> class FlavorOne : public Impl
>>> {
>>> private:
>>> void put (const Key &, const Data &) override {// do something}
>>> Data get (const Key &) const override {//do something}
>>>
>>> std::vector<Data> data;
>>> };
>>>
>>> FlavorOne flavorOne;
>>>
>>> class FlavorTwo : public Impl
>>> {
>>> private:
>>> void put (const Key &, const Data &) override {// do something}
>>> Data get (const Key &) const override {//do something}
>>>
>>> std::list<Data> data;
>>> };
>>>
>>> FlavorTwo flavorTwo;
>>>
>>> class FlavorThree : public Impl
>>> {
>>> private:
>>> void put (const Data &) override {// do something}
>>> Data get () const override {//do something}
>>>
>>> Std::deque<Data> data;
>>> };
>>>
>>> FlavorThree flavorThree;
>>>
>>> std::array<Storage &, 3> storage(flavorOne, flavorTwo, flavorThree);
>>> };
>>>
>>> Storage storage;
>>>
>>> To store some data: storage.put(data);
>>>
>>> -----Original Message-----
>>> From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf
>>> Of
>>> Thiago Macieira via Std-Proposals
>>> Sent: Sunday, April 5, 2026 10:04 AM
>>> To: std-proposals_at_[hidden]
>>> Cc: Thiago Macieira <thiago_at_[hidden]>
>>> Subject: Re: [std-proposals] Fwd: Extension to runtime polymorphism
>>> proposed
>>>
>>> On Saturday, 4 April 2026 23:57:02 Pacific Daylight Time Simon Schröder
>>> via
>>> Std-Proposals wrote:
>>> > Also, rvalues (if I’m not mistaken) go down to the IR and don’t
>>> > optimize on the level of the AST. If your optimizations can only be
>>> > done on the AST, this is certainly a totally different thing.
>>> >
>>> > Don’t just use “guaranteed semantics” as a buzz word, but actually
>>> > describe what you want to guarantee
>>>
>>> Muneem might be misusing "AST optimisation" term. If we put together the
>>> two
>>> above, what he may be proposing is like what rvalue references enabled:
>>> distinct functions that may be able to do more/different things than what
>>> existed before. That would be a difference in the AST, because it would
>>> be a
>>> different program altogether.
>>>
>>> However:
>>> a) I don't know if that's the case. There's no syntax proposed.
>>>
>>> b) even what little I understand doesn't match the problem in question of
>>> replacing a switch
>>>
>>> c) I don't buy that this is worth it, because without a clear
>>> explanation of
>>> where this solution would be used, it's impossible to judge its value
>>>
>>> The adding of even more seemingly unrelated things into the discussion,
>>> like
>>> virtual functions, does not help understanding what the problem is.
>>> Making
>>> imprecise statements that can be easily refuted only muddies the problem
>>> further.
>>>
>>> --
>>> Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
>>> Principal Engineer - Intel Data Center - Platform & Sys. Eng.
>>>
>>> --
>>> 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-05 22:44:15
