Date: Fri, 2 Jun 2023 08:38:11 +0300
Here is another very interesting case
https://devblogs.microsoft.com/cppblog/cpp23-deducing-this/#comment-2059
struct TaskDescriptor{
void submit(this std::unique_ptr<TaskDescriptor> self, const Executor& exec)
{ exec.submit(std::move(self)); }
// members};
auto desc = std::make_unique<TaskDescriptor>(...);
std::move(desc)->submit(exec);
Basically the need to call methods not on `this` *pointer* but on
`this`, *wrapped
inside an object*.
In a way, this is the reverse of class extensions scenario. There we extend
the API of an foreign object, here we create an API for our own object, but
we want to call it, having the object be part of another object.
In the end we "extend" the other object, but only as a side effect, not as
a primary goal (to have an extended API of the other object).
As per proposed, the above will be possible, no extra work needed, except,
the call site will be:
std::move(desc).TaskDescriptor::submit(exec);
On Thu, Jun 1, 2023 at 5:44 PM Михаил Найденов <mihailnajdenov_at_[hidden]>
wrote:
> Hello, with explicit object parameter we can have mixins as such:
>
> struct StringUtils {
> template<class T>
> void contains(this T self, char) { ... }
> };
>
> class MyString : public StringUtils {
> ...
> }
>
> We can also have half-baked extensions as such:
>
> struct StringUtils {
> void contains(this class MyString& self, char);
> };
>
> class MyString : public StringUtils {
> ...
> }
>
> void StringUtils::contains(this MyString& self, char) { ... }
>
> This is *almost **usable*. The fact that we need to subclass kills any
> perceived advantage as the extension becomes part of the
> implementation, making it no longer an extension.
> One is still better off writing a class-static function to get the extra
> functionality.
>
> This can be improved by allowing to *call * *StringUtils methods, which
> have the correct type of the `this` param or it is a template, without
> subclassing from it!*
>
> class MyString {
> ...
> }
>
> struct StringUtils {
> void contains(this MyString& self, char) { ... }
> };
>
> int main() {
> MyString s = "hello";
>
> s.::StringUtils::contains('e');
>
> return 0;
> }
>
> I am using the fully qualified access to show, there is *at least one* syntax
> that is *perfectly safe. *It might not be very practical, but it is a
> start.
> We can argue how we can improve it, what are the chances, subclasses can
> have the same name and/or what happens if other utilities are already in
> use. But at least with that particular syntax, no issues will ever arise.
> (Of course a performance argument can be made - now after the dot, many
> more classes become candidates, but it's a start...)
>
> And no, there is no UFC proposed.
> Just making use of the fact, the *explicit object parameter **already **does
> not point to a separate (new, with the introduced type) state! This is *
> *fundamentally** different then regular methods and the reason why this
> kind of classes **do not need subclassing **to be used by other classes. *All
> state is already defined by an external class, being a child of that class
> does not bring a structural difference.
>
>
>
https://devblogs.microsoft.com/cppblog/cpp23-deducing-this/#comment-2059
struct TaskDescriptor{
void submit(this std::unique_ptr<TaskDescriptor> self, const Executor& exec)
{ exec.submit(std::move(self)); }
// members};
auto desc = std::make_unique<TaskDescriptor>(...);
std::move(desc)->submit(exec);
Basically the need to call methods not on `this` *pointer* but on
`this`, *wrapped
inside an object*.
In a way, this is the reverse of class extensions scenario. There we extend
the API of an foreign object, here we create an API for our own object, but
we want to call it, having the object be part of another object.
In the end we "extend" the other object, but only as a side effect, not as
a primary goal (to have an extended API of the other object).
As per proposed, the above will be possible, no extra work needed, except,
the call site will be:
std::move(desc).TaskDescriptor::submit(exec);
On Thu, Jun 1, 2023 at 5:44 PM Михаил Найденов <mihailnajdenov_at_[hidden]>
wrote:
> Hello, with explicit object parameter we can have mixins as such:
>
> struct StringUtils {
> template<class T>
> void contains(this T self, char) { ... }
> };
>
> class MyString : public StringUtils {
> ...
> }
>
> We can also have half-baked extensions as such:
>
> struct StringUtils {
> void contains(this class MyString& self, char);
> };
>
> class MyString : public StringUtils {
> ...
> }
>
> void StringUtils::contains(this MyString& self, char) { ... }
>
> This is *almost **usable*. The fact that we need to subclass kills any
> perceived advantage as the extension becomes part of the
> implementation, making it no longer an extension.
> One is still better off writing a class-static function to get the extra
> functionality.
>
> This can be improved by allowing to *call * *StringUtils methods, which
> have the correct type of the `this` param or it is a template, without
> subclassing from it!*
>
> class MyString {
> ...
> }
>
> struct StringUtils {
> void contains(this MyString& self, char) { ... }
> };
>
> int main() {
> MyString s = "hello";
>
> s.::StringUtils::contains('e');
>
> return 0;
> }
>
> I am using the fully qualified access to show, there is *at least one* syntax
> that is *perfectly safe. *It might not be very practical, but it is a
> start.
> We can argue how we can improve it, what are the chances, subclasses can
> have the same name and/or what happens if other utilities are already in
> use. But at least with that particular syntax, no issues will ever arise.
> (Of course a performance argument can be made - now after the dot, many
> more classes become candidates, but it's a start...)
>
> And no, there is no UFC proposed.
> Just making use of the fact, the *explicit object parameter **already **does
> not point to a separate (new, with the introduced type) state! This is *
> *fundamentally** different then regular methods and the reason why this
> kind of classes **do not need subclassing **to be used by other classes. *All
> state is already defined by an external class, being a child of that class
> does not bring a structural difference.
>
>
>
Received on 2023-06-02 05:38:24