Date: Tue, 28 Apr 2026 15:36:38 +0200
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.)
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);
>> 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.
My understanding is that the additional information _Optional
conveys here is that the value of "ptr" is allowed to be null.
Yet, the syntactic placement of _Optional suggests that it's
making a statement about "int", the pointee.
Contrast that with _Atomic:
_Atomic int *x;
is talking about the atomic property of *x, not about those of
x itself. Why would
_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
> 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.)
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);
>> 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.
My understanding is that the additional information _Optional
conveys here is that the value of "ptr" is allowed to be null.
Yet, the syntactic placement of _Optional suggests that it's
making a statement about "int", the pointee.
Contrast that with _Atomic:
_Atomic int *x;
is talking about the atomic property of *x, not about those of
x itself. Why would
_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:36:43
