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,
B
is neither convertible toA
norint
, 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.