C++ Logo

std-proposals

Advanced search

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

From: Muneem <itfllow123_at_[hidden]>
Date: Sun, 12 Apr 2026 14:59:39 +0500
***question:***: how do you provide a class specialization specifically for
reference T, without breaking the rule that a name used by a class cant be
used for anything else in the same namespace/class/function scope.
> No, actually this would change the current workings of std::optional.
Currently, it throws if you call value() on it. Instead, we can also check
if there is a valid option and then use operator* (which is UB to use if it
doesn’t contain a value). The advantage of this approach is, that you do
not force anybody to use exceptions. Some people really don’t like them.
There is also no harm in constructing an empty optional when it is never
used.
**** Response ***:You have a point!
>Usually, if the template parameter is a T& we would implement it as a
pointer internally (just like you did). To the compiler, references and
pointers look the same anyway (it’s just that you cannot reassign a
reference to point to anything else). I think that this point is mostly
solved already. As I said, I’m not sure about the status of the proposal
for std::optional<T&>. But, exactly the same discussions would apply to
std::variant<T&…>.
**** Response ***: it's not problem solved if you allow references to be in
tagged unions like std::variant because references are by nature have all
their information known at compile time since its like a reference to an
variable, making them be in unions requires you to implement some sort of
support under the hood. There is a reason why references are only allowed
in structs, not in anything that is "union like", since such support
requires underlying pointers. Basically, it would be like variant<T*
const....> except that it would have a specific new specialization that
nothing depends on: std::variant<T..., reference_tag> and it can't hold
nullptrpointers?
>There is no branching needed. There are always two ways to specify
conversion: one would be to write an std::variant::operator=. However, we
would need to specify the desired type of the optional as a template
parameter. The easier solution would be:
template <Args&…>
std::optional<T&>::optional(std::variant<Args…> &variant)
    : m_storage(std::holds_alternative<T&>(variant) ? std::get<T&>(variant)
: std::nullopt)
{}
****Response***: 1. std::variant::operator= would still need branching
just like variants already have but would also need special support for
having references in "tagged unions" , and 2. holds_alternative<> cant be
passed references so again you do need some specialization of
hold_alternative, and again, how do you do that!?

A full proposal for this extension needs to discuss/consider a few things:
1. What kind of overloads do we need (const/non-const, &/&&)
2. Additional modifiers like constexpr and noexcept
3. Do we only propose this conversion just for std::optional<T&> or also
for std::optional<T>
4. What should happen if there are duplicate types inside the variant
(never happens with your use case)
5. Note that this does not compile if the type T& of the optional is not
one of the types of the variant
****RESPONSE****: How about I say:
1. We can provide overloads for tuple<T..., Runtime_index_tag> and
variant<T..., reference_tag>, like you cant I dont think I dont think you
can just provide a
std::variant<T...> without breaking the rule that a name used by a class
cant be used for anything else in the same namespace/class/function scope.
2. subscripting operations and constructor for the tuple<T...,
Runtime_index_tag> would be constexpr, with optimizations for the runtime
execution be provided through a branch set by "std::is_constant_evaluated".
For std::optional<T> , we need the same, that is a constexpr
constructor/assignment function that checks whether the variant has the
correct type or does it have any at all and throws a compiler error, while
a runtime version throws an error. This would of course require a
std::variant member consteval function "is compile time constructed" used
by that branch(the one branched by is_constant_evaluated), and a
std::variant constexpr constructor that sets the value returned by that to
true in its own "is_constant_evaluated==true" branch, but by default that
underlying value would be false. This provides a full set of optimizations
if any index into the tuple is constexpr.
3,. I would say provide for both std::optional<T> and std::optional<T> so
as to support some way of moving/copying the value of the variant.
4. tuple<T..., Runtime_index_tag> would have to return
std::variant<enable_if<std::is_same_v< Is_t_in_set <T, T...>, t true_t
>>...> as the return type of indexing, where in_t_in_set would obviously be
classic bjarne stourstrup style stuff:

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

>;

};
credits to him of course for such confusing(yet effective) techniques.
5. yeah, exactly, it should not compile if: type T passed to (as a
template arg) optional is not one of the types of the variant and to
enforce this, you could ofcourse use SFINAE:
template<typename T_of_optional>
struct optional< T_of_optional , reference_tag >{
//like optional<T&> but it is possible to exist thanks to the extra
reference_tag overload tag
typename<typename T..., template <typename T..., typename Tag> Variant_t>
enable_if<std::is_same_v< Is_t_in_set < T_of_optional , T...>, t true_t
> && std::is_same_v<T, reference_tag >>optional( Variant_t <T...,
reference_tag > ){
//now copy

}
}
again the code is just pseudo code, like just to give you an idea of what I
think, so the syntax maybe wrong


>For proposing std::variant<Ts&…> we should also discuss if a std::variant
should only be allowed to be either specified on only Ts… or Ts&…, or if we
allow a mixture of Ts and T-refs. (Certainly, for what you want just Ts&…
would suffice.) I’m not sure what the use case for a mixture would be, but
I also don’t see the point in artificially restricting them.
***Answer***: let's keep the separate, like technically a class can't know
for sure if some type can be reference or by value without a tag or
without different class names. Its not mechanically possible in the current
language facilities for variadic templates.
>Concerning the immutability of the selected type of a variant this is just
handled by making the variable of type std::variant const. There is no
std::variant::operator=() const, so we cannot reassign to a const
std::variant. Unfortunately, right now we also cannot reassign a value of
the proper type to a const std::variant (that’s just a syntactical/optical
deficiency).
***Answer***: so the overload for std::variant<T...,
reference_tag>::operator=() const should simply move/copy into the
underlying object pointed to by the reference?

>One more thing for std::variant: I want to be able to convert a
std::variant<int&,float&> to a std::variant<int,float> and also to an
std::optional<int>. This way the user of the type can choose between
getting a reference into the tuple or a copy of the value. (We need to
discuss if it makes sense to move values outside the tuple; this would be a
trap for UB.)
***ANSWER***: It won't be in the sense that if std::variant<int,float> is
const then you can only copy/assign to the underlying object whose type is
chosen during construction. For std::optional, its an exception if the user
prefers to be safe, but if he uses unsafe (but faster) methods then yeah,
undefined behaviour.

>Extending std::tuple with operator[] also needs one discussion: Do we only
allow this if all the types inside the tuple are distinct? I don’t see it
necessary for proposing this extension. However, I’d want for the
implementation of operator[] to make the types of the std::variant returned
to be distinct even if the types of std::tuple are not.
***ANSWER***: It does require a discussion, but what do you mean by
"distinct"? like in what way? is the variant gonna handle them differently?

On Sun, Apr 12, 2026 at 11:59 AM Simon Schröder <
dr.simon.schroeder_at_[hidden]> wrote:

>
>
> On Apr 11, 2026, at 2:23 PM, Muneem via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
> 
> On 4/10/26 20:01, Simon Schröder via Std-Proposals wrote:
> >std::optional<int&> x = list[0];
> Just to make sure that we are on the same page:
> we both agree that "std::optional<int&> x = list[index];"
> 1. std::optional<int&> 's constructor should throw an exception if the
> variant returned by list[index] is not an int.
>
> No, actually this would change the current workings of std::optional.
> Currently, it throws if you call value() on it. Instead, we can also check
> if there is a valid option and then use operator* (which is UB to use if it
> doesn’t contain a value). The advantage of this approach is, that you do
> not force anybody to use exceptions. Some people really don’t like them.
> There is also no harm in constructing an empty optional when it is never
> used.
>
> 2. For std::variant<T&...> to work, we need support from the
> implementation just like the support I needed for type_set<T...>, this
> support would be import such that we can avoid the T& to be changed, and
> since unions cant have references, the implementation would need to come up
> with some internal implementation.
>
> Usually, if the template parameter is a T& we would implement it as a
> pointer internally (just like you did). To the compiler references and
> pointers look the same anyway (it’s just that you cannot reassign a
> reference to point to anything else). I think that this point is mostly
> solved already. As I said, I’m not sure about the status of the proposal
> for std::optional<T&>. But, exactly the same discussions would apply to
> std::variant<T&…>.
>
>
> Note: the branching that I talked about for "std::variant<T&...>
> specialization to to some std::optional<T&> at runtime" in my email to
> Mr.David Brown is the checking in point one.
>
> There is no branching needed. There is always two ways to specify
> conversion: one would be to write an std::variant::operator=. However, we
> would need to specify the desired type of the optional as a template
> parameter. The easier solution would be:
> template <Args&…>
> std::optional<T&>::optional(std::variant<Args…> &variant)
> : m_storage(std::holds_alternative<T&>(variant) ?
> std::get<T&>(variant) : std::nullopt)
> {}
>
> A full proposal for this extension needs to discuss/consider a few things:
> 1. What kind of overloads do we need (const/non-const, &/&&)
> 2. Additional modifiers like constexpr and noexcept
> 3. Do we only propose this conversion just for std::optional<T&> or also
> for std::optional<T>
> 4. What should happen if there are duplicate types inside the variant
> (never happens with your use case)
> 5. Note that this does not compile if the type T& of the optional is not
> one of the types of the variant
>
> For proposing std::variant<Ts&…> we should also discuss if a std::variant
> should only be allowed to be either specified on only Ts… or Ts&…, or if we
> allow a mixture of Ts and T-refs. (Certainly, for what you want just Ts&…
> would suffice.) I’m not sure what the use case for a mixture would be, but
> I also don’t see the point in artificially restricting them.
>
> Concerning the immutability of the selected type of a variant this is just
> handled by making the variable of type std::variant const. There is no
> std::variant::operator=() const, so we cannot reassign to a const
> std::variant. Unfortunately, right now we also cannot reassign a value of
> the proper type to a const std::variant (that’s just a syntactical/optical
> deficiency).
>
> One more thing for std::variant: I want to be able to convert a
> std::variant<int&,float&> to a std::variant<int,float> and also to an
> std::optional<int>. This way the user of the type can choose between
> getting a reference into the tuple or a copy of the value. (We need to
> discuss if it makes sense to move values outside the tuple; this would be a
> trap for UB.)
>
> Extending std::tuple with operator[] also needs one discussion: Do we only
> allow this if all the types inside the tuple are distinct? I don’t see it
> necessary for proposing this extension. However, I’d want for the
> implementation of operator[] to make the types of the std::variant returned
> to be distinct even if the types of std::tuple are not.
>
>
> On 4/10/26 20:01, Bjorne Reese via Std-Proposals wrote:
> >> 2. Add operator[] to std::tuple which returns const std::variant<Ts&…>
>
> >Better yet, a free function that works with any tuple-like object.
>
> 1. I can agree that it will be convenient, but I would also love to
> emphasize that there should be a specific member function for the specific
> tuple<T&...> meant for runtime that has its own different implementation.
>
>
> @Bjorne: I do understand what you are saying here and why. I’m personally
> a little annoyed by the syntax of std::get. In general, I prefer the member
> access syntax (and we didn’t get automatic lookup of free-standing
> functions for this so far). Especially with the use of runtime indices it
> would be more consistent with arrays, vectors, etc. when using operator[]
> (and I like it better). Certainly, it looks like a proposal to extend
> std::tuple needs to discuss operator[] vs a free-standing function. We
> could also mix it and get both by having operator[] call the free-standing
> implementation.
>
>
> On Sat, Apr 11, 2026 at 10:21 AM Muneem <itfllow123_at_[hidden]> wrote:
>
>> My response my Mr.Thiago Let's forget the bench marks for a second, and
>> focus on the larger image of the limitations that I faced In implementing a
>> dynamic type system. Micro dispatches may not matter on a small scale but
>> it's like if if statements get slower then the effect is small in small
>> projects and large in large ones. Similiarly if you were to access variants
>> again and again and again, then you have the effect of the 13500% slower
>> speed increased. Again, dynamic typing is not a esoteric branch of
>> programming, infact as people move towards building large infrusture to
>> connect AI tools to automated scripts and to help them operate those tools,
>> we need real time systems, and real time systems often require flexibility
>> as they become complex. In the case of my virtual machine, it was meant to
>> be a simple way to build compilers but ended up having a whole large file
>> for dynamic typing. I would argue that the reason Python is used to deal
>> with large systems operated by AI or some other system is precisely because
>> it supports dynamic typing(cuz it's interpreted). In the case of python,
>> it's slow and the way it does dynamic typing is rather not strict
>> enough(duck typing behaviours) that though could be mitigated with newer
>> type constrained features are still causing issues in existing python code
>> bases. C++ on the other hands can support dynamic typing in way that allows
>> for strict closed set dynamic typing only. If that happens then people
>> would have no reason to use python over C++ in the majority of cases,
>> except the ones where you just want to automate a small task.
>>
>> On Fri, 10 Apr 2026, 8:02 pm Thiago Macieira via Std-Proposals, <
>> std-proposals_at_[hidden]> wrote:
>>
>>> On Friday, 10 April 2026 04:34:24 Pacific Daylight Time Muneem via Std-
>>> Proposals wrote:
>>> > Why do we need to go in circles? Like std::variant is a union hence not
>>> > STRICTLY DYNAMICALLY TYPED.
>>>
>>> No, it isn't. That depends on the code you write. You can very well
>>> operate
>>> only on the type it currently has, without changing.
>>>
>>> For the purpose you've espoused -- using one of many possible list
>>> implementations -- std::variant *works* *just* *fine*.
>>>
>>> From the analyses of the assembly generated by the compiler in the
>>> benchmarks
>>> you posted about a week ago, the difference is only where the "current
>>> type" is
>>> kept. With std::variant, since it is kept inside of the variant, the
>>> code
>>> emitted by the compiler ends up checking it every time. Quite likely, if
>>> you
>>> had two visitors back-to-back, the compiler would fail to realise it's
>>> the
>>> same current type and do two dispatches. That's a QoI problem and can be
>>> fixed
>>> in the compiler.
>>>
>>> With your external type selection, the compiler has an easier time
>>> proving the
>>> choice did not change and thus optimise the code to make a single
>>> dispatch to
>>> multiple visitors.
>>>
>>> That doesn't mean we need a new type. In real-world scenarios, the cost
>>> of
>>> extra dispatches is likely negligible -- as it was in the
>>> micro-benchmarks.
>>> There may be some edge cases where it is meaningful, but that does not
>>> imply
>>> the solution needs to be in the Standard Library. There are many
>>> specialised
>>> algorithms and containers that aren't due to their limited usefulness to
>>> the
>>> general public. Moreover, there is a cost in *adding* them: maintenance
>>> by the
>>> implementations, teachability, readability, etc.
>>>
>>> And more importantly, NONE of this implies we need a language change.
>>> That
>>> should be an orthogonal discussion.
>>>
>>> --
>>> 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
>
>

Received on 2026-04-12 09:59:54