From §4.2.7 of the proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#pathological-cases
It said that:
These are even more unlikely to be actually useful code. In this example,
Bis neither convertible toAnorint, so neither of these functions is even invocable using normal member syntax. However, you could take a pointer to such functions and invoke them through that pointer.(&B::bar)(42)is valid, if weird, call.
However, It does not specify whether the standard does not allow explicit object parameter of type-of-self implicitly convertible to particular another type.
struct A { };
struct B {
void foo(this A&);
void bar(this int);
};
Does that mean that:
struct A { };
struct B {
operator A() const noexcept;
void foo(this A);
};
// ...
// '&B::foo' is of type function pointer not pointer to member function
// because it uses explicit object parameter.
(&B::foo)(A{});
(&B::foo)(B{});
B{}.foo(); // will work?
will work?
In another case, here is a lambda. Since the type of the lambda is unutterable and is always dependent. What about the case above? (this captureless lambda is convertible to int(*)(int, int, int))
auto fib = [](this int(* self)(int, int, int), int n, int a = 0, int b = 1) {
return n == 0 ? a : n == 1 ? b : self(n - 1, b, a b);
};
Given that:
Non-member functions, static member functions, and explicit object member functions match targets of function pointer type or reference to function type. Non-static Implicit object member functions match targets of pointer-to-member-function type. ([over.match.viable] §12.2.3)
In all contexts, when converting to the implicit object parameter or when converting to the left operand of an assignment operation only standard conversion sequences are allowed. [Note: When converting to the explicit object parameter, if any, user-defined conversion sequences are allowed. - end note ] ([over.best.ics] §12.2.4.2)
CodePudding user response:
For your first question:
struct A { };
struct B {
operator A() const noexcept;
void foo(this A);
};
B{}.foo(); // will work?
Yes. Candidate lookup will find B::foo, which more or less evaluates as foo(B{}), which is valid due to the conversion function. This is explicitly called out in the note you cited, in [over.ics.best]/7:
[Note 5: When converting to the explicit object parameter, if any, user-defined conversion sequences are allowed. — end note]
This one is likewise valid, for the same reason:
auto fib = [](this int(* self)(int, int, int), int n, int a = 0, int b = 1) {
return n == 0 ? a : n == 1 ? b : self(n - 1, b, a b);
};
Although, this one seems exceedingly unlikely to be useful and you should probably never do this.
