为什么一个程序被拒绝为不明确的,可以通过重载决议来解决?
Why is a program rejected as ambiguous that could be resolved by overload resolution?
以下程序被 gcc 拒绝为不明确:
struct Aint
{
virtual void foo(int);
};
struct Astring
{
virtual void foo(std::string);
};
struct A: public Aint, public Astring {};
int main()
{
std::string s;
A a;
a.foo(s);
return 0;
}
> vt.cpp: In function ‘int main()’: vt.cpp:13:9: error: request for
> member ‘foo’ is ambiguous
> a.foo(s);
> ^ vt.cpp:5:34: note: candidates are: virtual void Astring::foo(std::__cxx11::string)
> struct Astring {virtual void foo(std::string);};
> ^ vt.cpp:4:31: note: virtual void Aint::foo(int)
> struct Aint {virtual void foo(int);};
Clang 始终出于同样的原因拒绝该程序:
clang -std=c++1y -c vt.cpp
vt.cpp:13:9: error: member 'foo' found in multiple base classes of different types
a.foo(s);
^
vt.cpp:4:31: note: member found by ambiguous name lookup
struct Aint {virtual void foo(int);};
^
vt.cpp:5:34: note: member found by ambiguous name lookup
struct Astring {virtual void foo(std::string);};
我不太确定我是否正确理解了10.2节中的查找规则,所以我将通过以下步骤中的规则来计算查找集S(foo, A):
1. A does not contain `foo`, so rule 5 applies and S(foo, A) is initially empty. We need to calculate the lookup sets S(foo, Aint) and S(foo, Afloat) and merge them to S(foo, A) = {}
2. S(foo, Aint) = {Aint::foo}
3. S(foo, Afloat) = {Afloat::foo}
4. Merge S(foo, Aint) = {Aint::foo} into S(foo, A) = {} to get S(foo, A) = {Aint::foo} (second case of 6.1)
5. Merge S(foo, Afloat) = {Afloat::foo} into {Aint::foo}. This create an ambiguous lookup set because of rule 6.2
结果集是无效集,因此程序格式错误。
我想知道为什么这个项目这么早就被拒绝了。在这种情况下,编译器应该很容易进行重载解析,因为两个函数具有相同的名称但签名不同,因此不存在真正的歧义。是否有技术原因不这样做,或者是否有其他原因会接受不正确的程序?有谁知道这么早就拒绝这些项目的决定背后的原因吗?
In C++, there is no overloading across scopes – derived class scopes are not an exception to this general rule .Please refer 了解更多详情。
无论如何,可以通过 "using" 关键字指定要使用两个版本的 foo 来改进您的示例。请参阅下面的示例。
示例程序:
#include <iostream>
#include <string>
struct Aint
{
void foo(int){std::cout<<"\n Aint";}
};
struct Astring
{
void foo(std::string){std::cout<<"\n Astring";}
};
struct A: public Aint, public Astring {
using Aint::foo;
using Astring::foo;
};
int main()
{
std::string s;
A a;
a.foo(s);
return 0;
}
output:Astring
以下程序被 gcc 拒绝为不明确:
struct Aint
{
virtual void foo(int);
};
struct Astring
{
virtual void foo(std::string);
};
struct A: public Aint, public Astring {};
int main()
{
std::string s;
A a;
a.foo(s);
return 0;
}
> vt.cpp: In function ‘int main()’: vt.cpp:13:9: error: request for
> member ‘foo’ is ambiguous
> a.foo(s);
> ^ vt.cpp:5:34: note: candidates are: virtual void Astring::foo(std::__cxx11::string)
> struct Astring {virtual void foo(std::string);};
> ^ vt.cpp:4:31: note: virtual void Aint::foo(int)
> struct Aint {virtual void foo(int);};
Clang 始终出于同样的原因拒绝该程序:
clang -std=c++1y -c vt.cpp
vt.cpp:13:9: error: member 'foo' found in multiple base classes of different types
a.foo(s);
^
vt.cpp:4:31: note: member found by ambiguous name lookup
struct Aint {virtual void foo(int);};
^
vt.cpp:5:34: note: member found by ambiguous name lookup
struct Astring {virtual void foo(std::string);};
我不太确定我是否正确理解了10.2节中的查找规则,所以我将通过以下步骤中的规则来计算查找集S(foo, A):
1. A does not contain `foo`, so rule 5 applies and S(foo, A) is initially empty. We need to calculate the lookup sets S(foo, Aint) and S(foo, Afloat) and merge them to S(foo, A) = {}
2. S(foo, Aint) = {Aint::foo}
3. S(foo, Afloat) = {Afloat::foo}
4. Merge S(foo, Aint) = {Aint::foo} into S(foo, A) = {} to get S(foo, A) = {Aint::foo} (second case of 6.1)
5. Merge S(foo, Afloat) = {Afloat::foo} into {Aint::foo}. This create an ambiguous lookup set because of rule 6.2
结果集是无效集,因此程序格式错误。
我想知道为什么这个项目这么早就被拒绝了。在这种情况下,编译器应该很容易进行重载解析,因为两个函数具有相同的名称但签名不同,因此不存在真正的歧义。是否有技术原因不这样做,或者是否有其他原因会接受不正确的程序?有谁知道这么早就拒绝这些项目的决定背后的原因吗?
In C++, there is no overloading across scopes – derived class scopes are not an exception to this general rule .Please refer 了解更多详情。 无论如何,可以通过 "using" 关键字指定要使用两个版本的 foo 来改进您的示例。请参阅下面的示例。
示例程序:
#include <iostream>
#include <string>
struct Aint
{
void foo(int){std::cout<<"\n Aint";}
};
struct Astring
{
void foo(std::string){std::cout<<"\n Astring";}
};
struct A: public Aint, public Astring {
using Aint::foo;
using Astring::foo;
};
int main()
{
std::string s;
A a;
a.foo(s);
return 0;
}
output:Astring