18

这段代码不能用 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++ 的一个错误?

4

2 回答 2

3

我会说不

至少:

§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 相当简洁......

于 2012-12-16T16:07:04.880 回答
2

根据第 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++ 违反了标准。

于 2012-12-17T10:45:08.753 回答