C++ 条件虚拟继承和对虚拟基成员的访问

C++ 条件虚拟继承和对虚拟基成员的访问,c++,inheritance,virtual-inheritance,C++,Inheritance,Virtual Inheritance,让我们看看下面的代码: 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 :

让我们看看下面的代码:

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 {};
第(1)行和第(2)行当然不会编译,这正是我想要的,但是如果我取消对第(X)行GCC 4.8.3和Clang 3.5.0的注释,则会使用以下消息拒绝代码:

错误:未在此作用域`#GCC中声明“str”
错误:使用未声明的标识符'str'`
为什么??我从B1或B2继承,我应该有权访问虚拟基成员。所以我在没有条件继承的情况下测试了它

template <typename T>
struct Z : B1, Empty {
    Z () : A ("Z ctor") {
        std::cout << str << std::endl;    // (Y)
    }
};
这对于这两种编译器来说都很好。在这种情况下,第(Y)行不会产生任何问题


如果使用条件继承,是否有任何原因导致无法访问虚拟基成员?还是某种编译器错误?

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)
    }
};
模板
结构X:虚拟A,
std::conditional::type,
std::conditional::type{
X():A(“X向量”){

std::cout这不是编译器错误。在您的示例中,
std::conditional::type
std::conditional::type
都是依赖的基类,因为它们依赖于模板参数
T
。如当前工作草案§14.6.2所述:

在类或类模板的定义中,在类模板或成员的定义点或类模板或成员的实例化过程中,未在非限定名称查找期间检查从属基类(14.6.2.1)的范围。[示例:

typedef双A;
B类模板{
类型定义INTA;
};
模板结构X:B{
A;//A的类型为double
};
X
定义中的类型名称
A
绑定到全局命名空间范围中定义的typedef名称,而不是基类
B
中定义的typedef名称-结束示例]

GCC和Clang正确地发出了一个错误,
str
未声明,因为编译器实际上是在声明
X
之前在全局范围内查找
str
的声明


您只需通过编写
this->str
A::str

“gcc 4.8.3和clang 3.5.0拒绝代码”来限定
str
,还可以包括在您的问题中发生拒绝时发出的逐字错误消息文本。(请回答您的问题;您知道这是如何工作的)一个猜想:条件继承使<代码> STR >依赖于<代码> t>代码>,因此您可能必须使用<代码> -> STR 访问它。编译器可能会考虑如果<代码> t>代码>有某种类类型。@ BPrassSon“条件继承使STR依赖于T,因此您可能必须使用-> STR访问它。”你说得对。这就解决了问题。这本质上是“什么是从属名称”或其他问题的重复。
template <typename T>
struct Z : B1, Empty {
    Z () : A ("Z ctor") {
        std::cout << str << std::endl;    // (Y)
    }
};
Z<int> z;
z.foo_b1 ();
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)
    }
};
typedef double A;
template<class T> class B {
    typedef int A;
};
template<class T> struct X : B<T> {
    A a; // a has type double
};