Date: Tue, 05 Aug 2025 11:57:25 -0400
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/
>>
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-05 15:57:36