让我们看看下面的代码:
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)没有任何问题。
如果使用条件继承,是否有任何理由无法访问虚拟基本成员?或者它是某种编译器错误?
答案 0 :(得分:2)
这不是编译器错误。在您的示例中,std::conditional<std::is_integral<T>::value, B1, Empty>::type
和std::conditional<std::is_floating_point<T>::value, B2, Empty>::type
都是依赖基类,因为它们依赖于模板参数T
。如当前工作草案§14.6.2中所述,n4527:
在类或类模板的定义中,在类模板或成员的定义点或在实例化实例化期间,在非限定名称查找期间不检查从属基类(14.6.2.1)的范围。类模板或成员。 [示例:
typedef double A; template<class T> class B { typedef int A; }; template<class T> struct X : B<T> { A a; // a has type double };
A
定义中的类型名X<T>
绑定到全局命名空间范围中定义的typedef名称,而不是基类B<T>
中定义的typedef名称。 - 结束示例]
GCC和Clang正在发出一个str
未声明的错误,因为编译器实际上是在str
声明之前尝试在全局范围内找到X
的声明。 / p>
您只需撰写str
或this->str
即可获得A::str
资格。
答案 1 :(得分:1)
str
是一个从属名称,因此您必须使用this->str
(或A::str
)。
或者你必须直接从A
继承:
template <typename T>
struct X : virtual A,
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)
}
};