C++ 在重载解析期间如何处理隐含对象参数?

C++ 在重载解析期间如何处理隐含对象参数?,c++,implicit-conversion,C++,Implicit Conversion,N4296::13.3.1/5[over.match.funcs]说明: 5在重载解析期间,隐含的对象参数为 与其他论点没有区别。隐式对象参数, 但是,自在相应的 参数应遵守以下附加规则: (5.1)-不能引入任何临时对象来支持 隐式对象参数;及 (5.2)-没有用户定义的转换 可以应用它来实现类型匹配 最后一个限制我不清楚,因为我认为候选函数集不可能包含两个或多个具有不同隐式对象参数的函数,因此有必要应用隐式转换来选择其中一个。例如: struct B { void foo(int a

N4296::13.3.1/5[over.match.funcs]
说明:

5在重载解析期间,隐含的对象参数为 与其他论点没有区别。隐式对象参数, 但是,自在相应的 参数应遵守以下附加规则:

(5.1)-不能引入任何临时对象来支持 隐式对象参数;及

(5.2)-没有用户定义的转换 可以应用它来实现类型匹配

最后一个限制我不清楚,因为我认为候选函数集不可能包含两个或多个具有不同隐式对象参数的函数,因此有必要应用隐式转换来选择其中一个。例如:

struct B
{
    void foo(int a){ }  
};

struct C
{
    void foo(int a){ }
};

struct A : B, C{ } a;

int main(){ a.foo(3); }

在本例中,只能应用隐式
派生到基
类转换。即使我们定义了显式转换,它也不会应用于隐含的对象参数


因此,不清楚引入了
5.2
规则的原因是什么?

5.2点表示存在用户定义的转换运算符。您没有提出这种情况,只是提出了对存在于两个基类中的成员函数的不明确调用,这涉及到从派生到基类的引用/指针转换,这是一种标准转换,而不是用户定义的转换,因此与5.2无关

5.2的目的是为了:

struct B
{
    void foo(int a){ }  
};

struct A {
    B b;
    operator B&() { return b; };
} a;

int main(){ 
    a.foo(3);                   // ERROR (because of 5.2)
    static_cast<B&>(a).foo(3);  // OK
}
结构B { void foo(int a){} }; 结构A{ B B; 运算符B&({return B;}); }a; int main(){ a、 foo(3);//错误(因为5.2) 静态_cast(a).foo(3);//确定 }
第5.2点仅仅意味着编译器不能尝试通过隐式用户定义的转换运算符(
运算符B&()
成员)最终找到候选的“foo”函数。这与foo是像
void foo(B&,int)
这样的自由函数并被
foo(a,3)
调用的情况相反,在这种情况下,编译器可以执行
a
B&
的转换,以发现foo函数是可接受的调用候选函数。这就是提出这一点的方式,因为成员函数版本与其等效自由函数版本之间的行为不同

因为我认为候选函数集不可能包含两个或更多具有不同隐式对象参数的函数


顺便说一句,你不需要有“两个或更多”来创建一组候选函数,一组候选函数也可以只包含一个函数,甚至一个函数都没有。正如Piotr S.所示,在这种特殊情况下,当然有可能造成一种情况,即多个候选对象可能具有不同的隐式对象参数类型。

名称查找无论如何都找不到
foo
。更好的例子是
A.B::foo()
,我想。@hvd不清楚,像
A.B::foo()
这样的构造已经被
N4296::5.2.5/2[expr.ref]
拒绝了。相关引用:表达式
E1->E2
转换为等价形式
(*(E1)).E2
5.2.5
的其余部分将只处理第一个选项(dot)。在这两种情况下,
id表达式
应命名类或其基类之一的成员。在您的例子中,
B::foo
既不是类的成员,也不是基类的成员。所以对我来说,这种限制仍然没有意义。你不能澄清一下吗?@DmitryFucintv我起初以为我同意你的看法,但实际上,我确实认为这个例子是正确的。如果没有您问题中的限制,
操作符的LHS将是
((B&)a)
(使隐式转换显式),并且
B::foo()
是该操作符的成员。“用户定义转换”包括转换构造函数