假设我有一个继承自两个不同类的类。他们都有一个像
using type_alias = int;
这样的别名。在班级范围内查找type_alias
应该是int
还是模棱两可?如果两个不同的类都从同一个类继承了该类型别名怎么办?
这里有一些其他的例子:
enum enum_type {
enumerator
};
template<int>
struct base {
using type_alias = int;
using enum enum_type;
};
struct derived : base<0>, base<1> {};
derived::type_alias main() {
return derived::enumerator;
}
derived::base<2> x; // injected-class-name
template<int>
struct super_base_template {};
struct super_base : super_base_template<0> {
using type_alias = int;
enum enum_type {
enumerator
};
static constexpr int static_member = 2;
};
template<int>
struct base : super_base {};
struct derived : base<0>, base<1> {};
derived::type_alias main() {
return derived::enumerator;
}
derived::super_base_template<derived::static_member> x;
clang 似乎能够编译所有这些,而 gcc 只喜欢它们是从字面上相同的声明继承的,例如第二个片段和第一个片段的最后一行。
以下哪些是有效的查找?
[class.member.lookup] 描述了如何在类的范围内搜索名称。与这个问题相关的部分是p5.2:
- 否则,如果 S(N, Bi) 和 S(N,C) 的声明集不同,则合并是不明确的...
对于表示同一实体的不同声明,措辞也不例外;即使找到的两个声明都是
using type_alias = int;
,查找也是不明确的。相反,如果只有一个声明(源自同一个基类),则该声明是查找的明确结果:
struct A { using X = int; };
struct B : A { using Y = int; };
struct C : A { using Y = int; };
struct D : B, C {};
D::X x; // OK
D::Y y; // ambiguous
关于具体示例:在第一个片段中,
derived::type_alias
如上所述是模棱两可的,derived::enumerator
明确引用了第二行enumerator
的声明:using enum enum_type;
等价于using enum_type::enumerator;
([enum.udecl]/2),查找时替换using-declarators通过他们命名的声明 ([basic.lookup.general]/3),derived::base
明确指代类模板 base
每 [temp.local]/4.在第二个片段的
derived::
中,每次查找都会找到一个声明,因此那里没有歧义。