【发布时间】:2015-12-24 04:42:43
【问题描述】:
让我们看看下面的代码:
struct A {
A (std::string s) : str {s} {}
A () = default;
std::string str {"XXX"};
};
struct B1 : virtual A {
B1 () = default;
void foo_b1 () {
std::cout << str << std::endl;
}
};
struct B2 : virtual A {
B2 () = default;
void foo_b2 () {
std::cout << str << std::endl;
}
};
struct Empty {};
到目前为止一切顺利,我希望类 A 有一个成员,该成员将在两个类 B1 和 B2 之间共享该实例(一个且只有一个),因此我按原样使用虚拟继承。下一步是从 B1 和 B2 进行条件继承,具体取决于模板参数 T,如下所示:
template <typename T>
struct X : std::conditional<std::is_integral<T>::value, B1, Empty>::type,
std::conditional<std::is_floating_point<T>::value, B2, Empty>::type {
X () : A ("X ctor") {
// std::cout << str << std::endl; // (X)
}
};
一切都很好,X 类的使用几乎是我想要的,所以我可以这样做:
X<int> x1;
x1.foo_b1 ();
x1.foo_b2 (); // (1)
X<double> x2;
x2.foo_b1 (); // (2)
x2.foo_b2 ();
第 (1) 行和第 (2) 行当然不会编译,这正是我想要的,但如果我取消注释第 (X) 行,GCC 4.8.3 和 Clang 3.5.0 会拒绝代码并显示消息:
error: ‘str’ was not declared in this scope` # GCC
error: use of undeclared identifier 'str'` # Clang
为什么?我从 B1 或 B2 继承,我应该可以访问虚拟基础成员。所以我在没有条件继承的情况下对其进行了测试。
template <typename T>
struct Z : B1, Empty {
Z () : A ("Z ctor") {
std::cout << str << std::endl; // (Y)
}
};
这样使用(当然这里不需要模板参数。类Z本身的行为类似于X<int>特化):
Z<int> z;
z.foo_b1 ();
这对两个编译器来说都很好。在这种情况下,行 (Y) 不会造成任何问题。
如果使用条件继承,是否有任何理由无法访问虚拟基成员?还是某种编译器错误?
【问题讨论】:
-
"gcc 4.8.3 和 clang 3.5.0 拒绝代码" - 也可以包括在您的问题中发生拒绝时发出的逐字错误消息文本。 (请在您的问题中提出;您知道这是如何工作的)。
-
猜测:条件继承使
str依赖于T,因此您可能必须使用this->str才能访问它。编译器可能会考虑如果T属于某种类类型会发生什么。 -
@BoPersson “条件继承使 str 依赖于 T,因此您可能必须使用 this->str 来访问它。”你说的对。这解决了问题。
-
这本质上是“什么是从属名称”的副本,或者任何该问题的名称。
标签: c++ inheritance virtual-inheritance