C++ 使用;使用;两次由不同的编译器进行不同的解释
考虑以下代码:C++ 使用;使用;两次由不同的编译器进行不同的解释,c++,c++11,C++,C++11,考虑以下代码: struct A { int propose(); }; struct A1 : A { int propose(int); using A::propose; }; struct B1 : A1 { protected: using A1::propose; public: using A::propose; }; int main() { B1().propose(); } 让我们编译一下:g++-std=c++11 m
struct A {
int propose();
};
struct A1 : A {
int propose(int);
using A::propose;
};
struct B1 : A1 {
protected:
using A1::propose;
public:
using A::propose;
};
int main() {
B1().propose();
}
让我们编译一下:g++-std=c++11 main.cpp
我在使用GNU 4.8.1时遇到以下编译器错误:
main.cpp: In function 'int main()':
main.cpp:2:9: error: 'int A::propose()' is inaccessible
int propose();
^
main.cpp:18:18: error: within this context
B1().propose();
但是,此代码在AppleClang 6.0.0.6000056中编译
我知道没有必要在
B1
中使用,(在我的代码中是必要的,但我有一个错误地使用了太多的)。无论如何,为什么Clang会编译它?这是预期的吗?在[namespace.udecl]中,我们有:
当using声明将名称从基类带入派生类作用域时,成员函数和
派生类中的成员函数模板重写和/或隐藏成员函数和成员函数
具有相同名称、参数类型列表(8.3.5)、cv限定和参考限定符(如有)的模板
基类(而不是冲突的)
标准明确规定引入的名称不会与基类中的名称冲突。但它并没有提到引入相互冲突的名字
该节还说:
using声明是一种声明,因此可以在多个(且仅在多个)位置重复使用
允许声明。[示例:
-[结束示例]
有趣的是,在下面的示例中,GCC很乐意编译它(并打印A),而Clang允许构造C,但拒绝调用foo,因为它不明确:
struct A {
void foo() { std::cout << "A\n"; }
};
struct B {
void foo() { std::cout << "B\n"; }
};
struct C : A, B {
using A::foo;
using B::foo;
};
int main()
{
C{}.foo();
return 0;
}
结构A{
void foo(){std::cout声明是合法的
调用它是合法的,应该可以在任何地方使用,并且只能从类和派生类中调用,并且可以从任何类中调用。您会注意到,这没有什么意义
没有规则禁止在声明中构造(从具有相同签名的两个不同基类中导入两次名称),甚至在派生类进入并在导入后隐藏名称的“实”代码中使用
如果您不隐藏它,您将处于一种奇怪的情况,即相同的函数A::propose
同时受保护和公开,因为它在同一范围内两次(合法)命名,具有不同的访问控制。这是不寻常的
如果您在一个类中,则子条款规定您可以使用它:
[class.access.base]/5.1
如果-(5.1)m作为N的成员是公共的,则当在类N中命名时,可以在点R处访问成员m
而且,提议
显然是公开的。(它也是受保护的
,但我们不必一直阅读该案例!)
在其他地方,我们有一个矛盾。你被告知你可以在任何地方不受限制地使用它[class.access]/1(3)。你被告知你只能在某些情况下使用它[class.access]/1(2)
我不确定如何解决这一模棱两可的问题
逻辑序列的其余部分:
在[namespace.udecl]/10中,我们有:
使用声明是一种声明,因此可以在允许(且仅限于)多个声明的情况下重复使用
和[namespace.udecl]/13:
由于using声明是一个声明,因此对同一声明区域中同名声明的限制
因此,使用X::propose;
的每个都是声明
[basic.scope]对一个作用域中同名的两个函数没有适用的限制,但[basic.scope.class]/1(3)除外,它指出,如果声明的重新排序改变了程序,则该程序是格式错误的。因此,我们不能说后一个程序获胜
在[basic.scope]下,同一作用域中的两个成员函数声明是合法的。但是,在[over]下,对同名的两个成员函数有限制
[超过]/1说明:
当为同一作用域中的单个名称指定两个或多个不同的声明时,该名称被称为重载
过载也有一些限制。这通常是防止过载的原因
struct foo {
int method();
int method();
};
不合法。但是:
[过载]/1表示:
并非所有函数声明都可以重载。此处指定了不能重载的函数声明。如果一个程序在同一范围内包含两个这样的不可重载声明,则该程序是格式错误的。[注意:这是
限制适用于范围内的显式声明,以及此类声明和通过使用声明(7.3.3)进行的声明之间的限制。它不适用于由于名称查找(例如,由于使用指令)或重载解析(例如,对于运算符函数)而制造的函数集。-结束注释
注释明确允许重载限制考虑通过两个using声明引入的符号!规则仅适用于范围内的两个显式声明,或范围内的显式声明和using声明之间的两个显式声明
对两个使用声明没有任何限制。它们可以具有相同的名称,并且它们的签名可以冲突到您想要的程度
这是很有用的,因为通常您可以转到并隐藏它们的声明(在派生类中使用声明),并且不会出错[namespace.udecl]/15:
当using声明将基类中的名称引入派生类作用域时,派生类中的成员函数和成员函数模板将覆盖和/或隐藏基类中具有相同名称、参数类型列表(8.3.5)、cv限定符和ref限定符(如果有)的成员函数和成员函数模板(而不是相互冲突)
但是,这里没有这样做。然后我们调用该方法。发生重载解析
请参见[namespace.udecl]/16:
为了解决过载问题,由
在派生类中使用声明将被视为是der的成员
struct foo {
int method();
int method();
};
protected:
int A::propose(); // X
int A1::propose(int); // Y
public:
int A::propose(); // Z