Date: Wed, 6 Aug 2025 20:25:34 +0800
Many thanks. Good to know of its existence. It really should come together
with deducing this....
On Tue, 5 Aug 2025 at 23:57, Julien Villemure-Fréchette via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> The solution exists in the version 2 C++ Extensions for Library
> Fundamentals. It might land in the standard at some point.
>
> See std::experimental::propagate_const:
> <https://en.cppreference.com/w/cpp/experimental/propagate_const.html>
>
> Instead of declaring the data member:
> T* data;
> declare it as:
> std::experimental::propagate_const<T*> data;
>
>
> On August 3, 2025 8:53:43 a.m. EDT, Yongwei Wu via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> There was a bug in the code. forward_pointer_like should be like:
>>
>> template <typename T, typename U>
>> constexpr auto forward_pointer_like(U* ptr)
>> {
>> constexpr bool is_adding_const =
>> is_const_v<remove_reference_t<T>>;
>> if constexpr (is_adding_const != is_const_v<U>) {
>> if constexpr (is_adding_const) {
>> return const_cast<const U*>(ptr);
>> } else {
>> return const_cast<remove_const_t<U>*>(ptr);
>> }
>> } else {
>> return ptr;
>> }
>> }
>>
>> On Sun, 3 Aug 2025 at 14:09, Yongwei Wu <wuyongwei_at_[hidden]> wrote:
>>
>>> While deducing this can be useful in some scenarios, it is prone to
>>> misuse. A simplified case is as follows:
>>>
>>> template <typename T>
>>> class Container {
>>> public:
>>> // …
>>> template <typename Self>
>>> auto data(this Self&& self) noexcept
>>> {
>>> return self.data_;
>>> }
>>>
>>> private:
>>> T* data_;
>>> };
>>>
>>> Generally you want the data() member function to give you a const T* on
>>> a const container, but this implementation will always give you T*.
>>> I nearly wrote such code in an article, and I *actually* saw similar
>>> code in a recently published C++ book.
>>>
>>> I think a utility function (as well as education materials) is useful in
>>> such cases. Modelling forward_like, probably something like:
>>>
>>> template <typename T, typename U>
>>> constexpr auto forward_pointer_like(U* ptr)
>>> {
>>> constexpr bool is_adding_const =
>>> is_const_v<remove_reference_t<T>>;
>>> if constexpr (is_const_v<remove_reference_t<T>> !=
>>> is_adding_const) {
>>> if constexpr (is_adding_const) {
>>> return const_cast<const U*>(ptr);
>>> } else {
>>> return const_cast<remove_const_t<U>*>(ptr);
>>> }
>>> } else {
>>> return ptr;
>>> }
>>> }
>>>
>>> Related idea: Should we just update as_const to make it generate a const
>>> T* given a T*? This could be an easy fix that allows us to simply use
>>> forward_like, but I am not sure whether it can break things.
>>>
>>> What do you think? Did I miss something already existing in the standard?
>>>
>>> --
>>> Yongwei Wu
>>> URL: http://wyw.dcweb.cn/
>>>
>>
with deducing this....
On Tue, 5 Aug 2025 at 23:57, Julien Villemure-Fréchette via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> The solution exists in the version 2 C++ Extensions for Library
> Fundamentals. It might land in the standard at some point.
>
> See std::experimental::propagate_const:
> <https://en.cppreference.com/w/cpp/experimental/propagate_const.html>
>
> Instead of declaring the data member:
> T* data;
> declare it as:
> std::experimental::propagate_const<T*> data;
>
>
> On August 3, 2025 8:53:43 a.m. EDT, Yongwei Wu via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> There was a bug in the code. forward_pointer_like should be like:
>>
>> template <typename T, typename U>
>> constexpr auto forward_pointer_like(U* ptr)
>> {
>> constexpr bool is_adding_const =
>> is_const_v<remove_reference_t<T>>;
>> if constexpr (is_adding_const != is_const_v<U>) {
>> if constexpr (is_adding_const) {
>> return const_cast<const U*>(ptr);
>> } else {
>> return const_cast<remove_const_t<U>*>(ptr);
>> }
>> } else {
>> return ptr;
>> }
>> }
>>
>> On Sun, 3 Aug 2025 at 14:09, Yongwei Wu <wuyongwei_at_[hidden]> wrote:
>>
>>> While deducing this can be useful in some scenarios, it is prone to
>>> misuse. A simplified case is as follows:
>>>
>>> template <typename T>
>>> class Container {
>>> public:
>>> // …
>>> template <typename Self>
>>> auto data(this Self&& self) noexcept
>>> {
>>> return self.data_;
>>> }
>>>
>>> private:
>>> T* data_;
>>> };
>>>
>>> Generally you want the data() member function to give you a const T* on
>>> a const container, but this implementation will always give you T*.
>>> I nearly wrote such code in an article, and I *actually* saw similar
>>> code in a recently published C++ book.
>>>
>>> I think a utility function (as well as education materials) is useful in
>>> such cases. Modelling forward_like, probably something like:
>>>
>>> template <typename T, typename U>
>>> constexpr auto forward_pointer_like(U* ptr)
>>> {
>>> constexpr bool is_adding_const =
>>> is_const_v<remove_reference_t<T>>;
>>> if constexpr (is_const_v<remove_reference_t<T>> !=
>>> is_adding_const) {
>>> if constexpr (is_adding_const) {
>>> return const_cast<const U*>(ptr);
>>> } else {
>>> return const_cast<remove_const_t<U>*>(ptr);
>>> }
>>> } else {
>>> return ptr;
>>> }
>>> }
>>>
>>> Related idea: Should we just update as_const to make it generate a const
>>> T* given a T*? This could be an easy fix that allows us to simply use
>>> forward_like, but I am not sure whether it can break things.
>>>
>>> What do you think? Did I miss something already existing in the standard?
>>>
>>> --
>>> Yongwei Wu
>>> URL: http://wyw.dcweb.cn/
>>>
>>
Received on 2025-08-06 12:25:50