这段代码不能用 GCC4.7 编译
struct A {};
void f(A);
struct B { B(std::tuple<A>); };
void f(B);
int main() {
f(std::make_tuple(A()));
}
因为GCC派生自A
利用空基类优化。然而,这导致 GCC 挑剔f(A)
和抱怨
错误:
'A'
是一个不可访问的基础'tuple<A>'
这个错误是由 C++ 标准授予的还是仅仅是 libstdc++ 的一个错误?
这段代码不能用 GCC4.7 编译
struct A {};
void f(A);
struct B { B(std::tuple<A>); };
void f(B);
int main() {
f(std::make_tuple(A()));
}
因为GCC派生自A
利用空基类优化。然而,这导致 GCC 挑剔f(A)
和抱怨
错误:
'A'
是一个不可访问的基础'tuple<A>'
这个错误是由 C++ 标准授予的还是仅仅是 libstdc++ 的一个错误?
我会说不。
至少:
§20.4.1 [tuple.general]
1/ [...] 具有两个参数的 tuple 实例化类似于具有相同两个参数的 pair 实例化。见 20.3。
但是:
#include <tuple>
struct A {};
void f(A);
struct B { B(std::tuple<A, A>); };
void f(B);
int main() {
f(std::make_tuple(A(), A()));
}
失败:
Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:10:30: error: 'A' is an ambiguous base of 'std::tuple<A, A>'
source.cpp:4:6: error: initializing argument 1 of 'void f(A)'
我非常怀疑这是标准的意图。
尽管如此,至少可以说 §20.4 相当简洁......
根据第 17 条图书馆介绍:
17.5.2.3 私有成员[objects.within.classes]
1 - 第 18 到 30 条和附录 D 没有指定类的表示,并且有意省略了类成员的说明。实现可以定义静态或非静态类成员,或两者,根据需要实现第 18 到 30 条和附录 D 中指定的成员函数的语义。
这得到1.4 实施合规性 [intro.compliance]的支持:
3 - 对于类和类模板,库子句指定部分定义。未指定私有成员(第 11 条),但每个实现都应提供它们以根据库条款中的描述完成定义。
在第 17 节的任何地方都没有明确讨论通过继承实现指定的语义,但通过上面 17.5.2.3 的第 3 段隐含地允许这样做:
3 - 实现可以使用任何提供等效外部行为的技术。
例如,这就是基于节点的有序关联容器如何通过继承共享实现细节(最终包括类成员)。
tuple
由于在作为类成员和直接继承它之间的外部行为发生了变化A
,并且由于这种行为变化导致拒绝其他格式良好的程序(而不是仅仅改变sizeof
类的),所以 libstdc++ 违反了标准。