Date: Sat, 19 Mar 2022 17:43:53 +0000
> This is actually a significant reason to not do this. We specifically changed view_interface<D> to avoid inheriting from view_base to reduce the number of view_base objects in range adaptors (https://cplusplus.github.io/LWG/issue3549)... this would just reintroduce that problem.
I'm not sure it would "just reintroduce" it per se, but it would increase the prevalence for sure. Maybe the deduced "this" form could be specified differently, such as
template<typename Unique = decltype([] {})>
struct __deduced_this_tag { };
template<typename Derived = __deduced_this_tag<>>
struct view_interface {
/* ... */
};
Where when Derived is a specialization of __deduced_this_tag, then it will use the deduced "this" pattern. Because of the lambda in __deduced_this_tag, each view_interface<> instantiation should be a unique type.
> The benefits here seem fairly minimal. The code duplication is in the standard library implementations, and that's already written - it's not something the user has to care about. Is the benefit just that you can write:
>
> template <typename... Ts> struct zip_view : view_interface<> { ... }
>
> instead of:
>
> template <typename... Ts> struct zip_view : view_interface<zip_view<Ts...>> { ... }
> If so, yeah, it's annoying to have to do - especially to have to repeat the template parameters. But that's a one time nuisance, versus the added storage burden for every adaptor?
I will agree, the benefits aren't groundbreaking, but I think it would be a pretty good quality of life change, for both writing code and reading code. Additionally, creating views isn't just for the STL, especially if after C++23 users are more able to create their own range adaptors. And the "one time nuisance" of specifying the whole type again can turn into more than one time if you change the template parameters or the type name, which isn't much of a concern for the STL, but could be for users.
(Sorry, I accidentally only replied to Barry)
------- Original Message -------
On Friday, March 18th, 2022 at 11:36 PM, Barry Revzin <barry.revzin_at_[hidden]> wrote:
> On Fri, Mar 18, 2022 at 1:03 PM Keenan Horrigan via Std-Proposals <std-proposals_at_[hidden]> wrote:
>
>> Hi, I was wondering if it would make sense to add deduced "this" to already-existing CRTP interfaces, such as std::ranges::view_interface. I was thinking for instance it could be changed to
>>
>> template<typename Derived = void>
>> struct view_interface {
>> /* ... */
>> };
>>
>> where for all now-existing uses of view_interface it would function as normal, with the inheriting class specified in the template instantiation, but new classes could do e.g.
>>
>> template</* Potentially several lengthy template parameters */>
>> struct my_view : std::ranges::view_interface<> {
>> /* ... */
>> };
>>
>> which would instantiate std::ranges::view_interface<void> which would take advantage of the new deduced "this" pattern, cutting down on code duplication and over-verbosity.
>>
>> I don't think this would be an API-breaking change, and I'm pretty sure this wouldn't be ABI-breaking either since no one should have instantiated a std::ranges::view_interface<void>, but even if they did then they wouldn't be able to really do anything with it.
>>
>> This change though would increase the number of views with a shared parent class (std::ranges::view_interface<void>) which might stop space optimizations because two objects of the same type can't share the same space, even with [[no_unique_address]] (at least as I understand it). I personally don't find that to be a compelling counterargument though, especially with std::ranges::view_base already existing.
>
> This is actually a significant reason to not do this. We specifically changed view_interface<D> to avoid inheriting from view_base to reduce the number of view_base objects in range adaptors (https://cplusplus.github.io/LWG/issue3549)... this would just reintroduce that problem.
>
>> But then there's also that the deduced "this" pattern could deduce a class that derives from "my_view" from the earlier example, which seems like a thing to keep in mind for any instance of using deduced "this" in a CRTP way, but still the question remains of is that a problem, and if so, is it enough to outweigh the benefits of this change? I personally am not sure.
>>
>> I would love to hear others' input on this idea, thank you in advance.
>
> The benefits here seem fairly minimal. The code duplication is in the standard library implementations, and that's already written - it's not something the user has to care about. Is the benefit just that you can write:
>
> template <typename... Ts> struct zip_view : view_interface<> { ... }
>
> instead of:
>
> template <typename... Ts> struct zip_view : view_interface<zip_view<Ts...>> { ... }
>
> If so, yeah, it's annoying to have to do - especially to have to repeat the template parameters. But that's a one time nuisance, versus the added storage burden for every adaptor?
>
> Barry
I'm not sure it would "just reintroduce" it per se, but it would increase the prevalence for sure. Maybe the deduced "this" form could be specified differently, such as
template<typename Unique = decltype([] {})>
struct __deduced_this_tag { };
template<typename Derived = __deduced_this_tag<>>
struct view_interface {
/* ... */
};
Where when Derived is a specialization of __deduced_this_tag, then it will use the deduced "this" pattern. Because of the lambda in __deduced_this_tag, each view_interface<> instantiation should be a unique type.
> The benefits here seem fairly minimal. The code duplication is in the standard library implementations, and that's already written - it's not something the user has to care about. Is the benefit just that you can write:
>
> template <typename... Ts> struct zip_view : view_interface<> { ... }
>
> instead of:
>
> template <typename... Ts> struct zip_view : view_interface<zip_view<Ts...>> { ... }
> If so, yeah, it's annoying to have to do - especially to have to repeat the template parameters. But that's a one time nuisance, versus the added storage burden for every adaptor?
I will agree, the benefits aren't groundbreaking, but I think it would be a pretty good quality of life change, for both writing code and reading code. Additionally, creating views isn't just for the STL, especially if after C++23 users are more able to create their own range adaptors. And the "one time nuisance" of specifying the whole type again can turn into more than one time if you change the template parameters or the type name, which isn't much of a concern for the STL, but could be for users.
(Sorry, I accidentally only replied to Barry)
------- Original Message -------
On Friday, March 18th, 2022 at 11:36 PM, Barry Revzin <barry.revzin_at_[hidden]> wrote:
> On Fri, Mar 18, 2022 at 1:03 PM Keenan Horrigan via Std-Proposals <std-proposals_at_[hidden]> wrote:
>
>> Hi, I was wondering if it would make sense to add deduced "this" to already-existing CRTP interfaces, such as std::ranges::view_interface. I was thinking for instance it could be changed to
>>
>> template<typename Derived = void>
>> struct view_interface {
>> /* ... */
>> };
>>
>> where for all now-existing uses of view_interface it would function as normal, with the inheriting class specified in the template instantiation, but new classes could do e.g.
>>
>> template</* Potentially several lengthy template parameters */>
>> struct my_view : std::ranges::view_interface<> {
>> /* ... */
>> };
>>
>> which would instantiate std::ranges::view_interface<void> which would take advantage of the new deduced "this" pattern, cutting down on code duplication and over-verbosity.
>>
>> I don't think this would be an API-breaking change, and I'm pretty sure this wouldn't be ABI-breaking either since no one should have instantiated a std::ranges::view_interface<void>, but even if they did then they wouldn't be able to really do anything with it.
>>
>> This change though would increase the number of views with a shared parent class (std::ranges::view_interface<void>) which might stop space optimizations because two objects of the same type can't share the same space, even with [[no_unique_address]] (at least as I understand it). I personally don't find that to be a compelling counterargument though, especially with std::ranges::view_base already existing.
>
> This is actually a significant reason to not do this. We specifically changed view_interface<D> to avoid inheriting from view_base to reduce the number of view_base objects in range adaptors (https://cplusplus.github.io/LWG/issue3549)... this would just reintroduce that problem.
>
>> But then there's also that the deduced "this" pattern could deduce a class that derives from "my_view" from the earlier example, which seems like a thing to keep in mind for any instance of using deduced "this" in a CRTP way, but still the question remains of is that a problem, and if so, is it enough to outweigh the benefits of this change? I personally am not sure.
>>
>> I would love to hear others' input on this idea, thank you in advance.
>
> The benefits here seem fairly minimal. The code duplication is in the standard library implementations, and that's already written - it's not something the user has to care about. Is the benefit just that you can write:
>
> template <typename... Ts> struct zip_view : view_interface<> { ... }
>
> instead of:
>
> template <typename... Ts> struct zip_view : view_interface<zip_view<Ts...>> { ... }
>
> If so, yeah, it's annoying to have to do - especially to have to repeat the template parameters. But that's a one time nuisance, versus the added storage burden for every adaptor?
>
> Barry
Received on 2022-03-19 17:43:56