显式对象参数是否允许可转换类型?
Does Explicit Object Parameter Allow Convertible Types?
来自提案的 §4.2.7 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#pathological-cases
它说:
These are even more unlikely to be actually useful code. In this example, B
is neither convertible to A
nor int
, 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.
但是,它没有指定标准是否不允许显式对象参数的自类型隐式转换为特定的另一种类型。
struct A { };
struct B {
void foo(this A&);
void bar(this int);
};
这是否意味着:
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?
有用吗?
在另一种情况下,这是一个 lambda。由于 lambda 的类型是不可言说的并且总是依赖的。上面的案例呢? (此无捕获 lambda 可转换为 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);
};
鉴于:
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)
第一个问题:
struct A { };
struct B {
operator A() const noexcept;
void foo(this A);
};
B{}.foo(); // will work?
是的。候选查找将找到 B::foo
,或多或少地评估为 foo(B{})
,由于转换功能,它是有效的。您在 [over.ics.best]/7:
中引用的注释中明确指出了这一点
[Note 5: When converting to the explicit object parameter, if any, user-defined conversion sequences are allowed. — end note]
这个,其实我不是很确定:
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);
};
它似乎极不可能有用,你可能永远不应该这样做,所以我不知道它是否真的有效很重要。但我也不确定这样的例子意味着什么:
struct C {
C(auto);
void f();
};
auto lambda = [](this C c) { c.f(); }; // OK?
如果这可以转换为函数指针,那么函数指针的类型到底是什么?如果是 void(*)()
,那么我们在哪个 C
上调用 f()
?所以它必须是 void(*)(C)
,在这种情况下 fib
示例肯定不起作用,因为不可能以匹配的方式拼写函数指针类型 non-generically。
来自提案的 §4.2.7 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#pathological-cases
它说:
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.
但是,它没有指定标准是否不允许显式对象参数的自类型隐式转换为特定的另一种类型。
struct A { };
struct B {
void foo(this A&);
void bar(this int);
};
这是否意味着:
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?
有用吗?
在另一种情况下,这是一个 lambda。由于 lambda 的类型是不可言说的并且总是依赖的。上面的案例呢? (此无捕获 lambda 可转换为 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);
};
鉴于:
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)
第一个问题:
struct A { };
struct B {
operator A() const noexcept;
void foo(this A);
};
B{}.foo(); // will work?
是的。候选查找将找到 B::foo
,或多或少地评估为 foo(B{})
,由于转换功能,它是有效的。您在 [over.ics.best]/7:
[Note 5: When converting to the explicit object parameter, if any, user-defined conversion sequences are allowed. — end note]
这个,其实我不是很确定:
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);
};
它似乎极不可能有用,你可能永远不应该这样做,所以我不知道它是否真的有效很重要。但我也不确定这样的例子意味着什么:
struct C {
C(auto);
void f();
};
auto lambda = [](this C c) { c.f(); }; // OK?
如果这可以转换为函数指针,那么函数指针的类型到底是什么?如果是 void(*)()
,那么我们在哪个 C
上调用 f()
?所以它必须是 void(*)(C)
,在这种情况下 fib
示例肯定不起作用,因为不可能以匹配的方式拼写函数指针类型 non-generically。