C++ Logo

liaison

Advanced search

Re: [isocpp-wg14/wg21-liaison] qualifier and type deduction

From: Martin Uecker <ma.uecker_at_[hidden]>
Date: Tue, 28 Apr 2026 15:56:56 +0200
Am Dienstag, dem 28.04.2026 um 15:36 +0200 schrieb Jens Maurer:
>
> On 4/28/26 15:05, Martin Uecker wrote:
> > Am Dienstag, dem 28.04.2026 um 13:11 +0200 schrieb Jens Maurer via Liaison:
> > >
> > > On 4/28/26 12:45, Aaron Ballman via Liaison wrote:
> > > > On Mon, Apr 27, 2026 at 3:51 PM Martin Uecker via Liaison
> > > > <liaison_at_[hidden]> wrote:
> > > > >
> > > > >
> > > > >
> > > > > Hi,
> > > > >
> > > > > n3876.pdf has the following example:
> > > > >
> > > > >
> > > > > template <typename Ty>
> > > > > void func(Ty *ptr, Ty val);
> > > > >
> > > > > _Optional int *ptr = foo();
> > > > > func(ptr, 12);
> > > > >
> > > > >
> > > > > as an example why the qualifier is at the "wrong" position
> > > > > and this would cause problems for C++. It states
> > > > >
> > > > > "When the qualifier is correctly associated with the pointer
> > > > > rather than the pointee, the semantics work as a C++ programmer
> > > > > would expect and Ty would deduce unambiguously to int"
> > > > >
> > > > > But if you replace "_Optional" with "const" the example also fails
> > > > > deduce unambigously. So is "const" also in the wrong location?
> > > > >
> > > > > Can somebody explain me what the authors mean?
> > > >
> > > > Ah, I can see how this wasn't worded clearly; "correctly associated"
> > > > was meant to imply changes to the code. But what we were trying to say
> > > > was: By applying the qualifier effects on the pointer despite being
> > > > written on the pointee, you create problems for type generic code like
> > > > that because it's an ambiguous deduction depending on the qualifier.
> > > > e.g., calling with _Optional int * and calling with const int * will
> > > > deduce differently under the proposed model were it to be supported in
> > > > C++ and we think they should deduce the same way (and be ambiguous in
> > > > that code example). We think users should write this instead:
> > > >
> > > > template <typename Ty>
> > > > void func(Ty *ptr, Ty val);
> > > >
> > > > int * _Optional ptr = foo();
> > > > func(ptr, 12);
> > > >
> > > > so that `Ty` deduces to `int` unambiguously, same as would happen with
> > > > `const` in that qualifier position.
> >
> > Sorry, I still do not undertand this. We also put "const" on the
> > pointer target in function interfaces. The qualifier on the argument
> > itself does become part of the type of the function.
> >
> > So are you saying "const" also causes problems for type generic code
> > and qualifiers are generally a problem in C++?
>
> Not really.
>
> Consider:
>
> const /* 1 */ int * const /* 2 */ ptr = foo();
>
>
> There are two ways to place a "const" here, and each syntactic location
> has its implied meaning.
>
> "const" at position 2 means you can't modify the "ptr" variable
> going forward.

> "const" at position 1 means you can't modify the object to which
> the value of "ptr" points (using this particular access path).
> (Yes, the object itself might be non-const, but that's not in the
> picture here.)

Yes.
>
>
> In Aaron's and my alternate world, we'd need a more nuanced brush for
> "dropping qualifiers" when forming the signature of a function in C.
>
> void f(int * const); === void f(int *);
>
> But maybe don't drop the _Optional here when forming the signature:
>
> void f(int * _Optional);

But "not dropping the qualifier" would follow naturally when putting
it on the pointee. So this would seem to give you the right semantics
using existing language mechanisms when putting on the pointee. So now
I am even more confused about what the problem is.


> > > Agreed; it's the pointer value that has a property (can it be null),
> > > not the pointee.
> >
> > This is not how qualifiers work in C. They control the access rules
> > to an object and do not describe a property of the object itself.
>
> Agreed as far as const and volatile are concerned (also for C++).
> However, how does this statement apply to _Optional?
>
> Which objects are in view when we talk about
>
> _Optional int * ptr = foo();
>
> ?
>
> Assuming _Optional is a "qualifier" in your parlance.
>
> As far as I can see, there is one object here for sure,
> and that's the object that is named "ptr" here (the pointer).
> Either "ptr" is null, in which case there is no other object,
> or "ptr" is not null, in which case there's another object
> (ignore the past-the-end of an array case): the object to
> which "ptr" points.

This is more a philosophical argument. You could argue that
"const" on the pointer also makes no sense as there might be
no object that is const if the pointer is a null pointer.

But neither "const", "volatile" nor "_Optional" describe a
property of an object, they all describe semantics of an
access to an object using the giving type of the lvalue.

For "const" it says you can not write using that lvalue,
for "volatile" it says that all accesses appear according
to the rules of the abstract machine, and for "_Optional"
it says that an access without prior null pointer check
is forbidden.

Whether the term "_Optional" is ideal to capture this ideas
is possibly a different question.

>
> My understanding is that the additional information _Optional
> conveys here is that the value of "ptr" is allowed to be null.

This interpretation may not be the right one to understand
the proposal.

A traditional qualifier would also not be the right concept
to transfer information about possible values, because
then you would certainly want to preserve them during lvalue
conversion because the rvalue would have the same set of
values. So you would want something such as a
"sub-type specifier" that restricts the possible values.

But even this would not make sense for _Optional, as saying
a pointer can be null does not change its sets of values and
provides zero information.

So I can only encourage people to look at this from a different
perspective, and not try to understand this as a restriction
of possible values of a type.

>
> Yet, the syntactic placement of _Optional suggests that it's
> making a statement about "int", the pointee.

Yes, and it does in the sense explained above.

>
> Contrast that with _Atomic:
>
> _Atomic int *x;
>
> is talking about the atomic property of *x, not about those of
> x itself. Why would

Yes, but _Atomic also does not change the set of values of 'x',
but tells you something about how it is accessed. (sadly it
is a bit broken as it is not a true qualifier).


Martin
>
> _Optional int *y;
>
> talk about the null-able properties of y ?
>
> > This is also why they are dropped during lvalue conversion and do
>
> adding "not"
>
> > become part of the function type, both would make no sense if they
> > described properties of an object instead of an access to an object.
>
> Sure.
>
> Jens

Received on 2026-04-28 13:57:05