我很惊讶GCC 不认为以下程序中对foo()
的调用不明确:
#include <iostream>
struct B1 { bool foo(bool) { return true; } };
struct B2 { bool foo(bool) { return false; } };
struct C : public B1, public B2
{
using B1::foo;
using B2::foo;
};
int main()
{
C c;
// Compiles and prints `true` on GCC 4.7.2 and GCC 4.8.0 (beta);
// does not compile on Clang 3.2 and ICC 13.0.1;
std::cout << std::boolalpha << c.foo(true);
}
上面的函数调用在GCC 4.7.2和GCC 4.8.0(beta)上编译并返回true
,而将无法编译(如我所料)在Clang上3.2和ICC 13.0.1。
这是“无需诊断”的情况,还是GCC中的错误?鼓励参考C ++ 11标准。
答案 0 :(得分:4)
§7.3.3/ 3:
在用作成员声明的using声明中,嵌套名称说明符应命名要定义的类的基类。如果这样的using-declaration命名一个构造函数,那么nested-name-specifier应该命名一个被定义的类的直接基类;否则它引入了成员名称查找(10.2,3.4.3.1)找到的声明集。
¶14:
... [注意:两个using声明可能会引入具有相同名称和相同参数类型的函数。如果对于非限定函数名的调用,函数重载决策选择了这种使用声明引入的函数,则函数调用是不正确的。
¶16:
出于重载解析的目的,将using声明引入的函数 派生类将被视为派生类的成员。
所以,using
声明是合法的,但是函数是同一个重载集中的对等体,如你所说,并且程序格式不正确。
答案 1 :(得分:1)
正如您所说,您的计划中对foo(true)
的调用显然是模棱两可的;此外,根据§10.2中提出的算法,它是模糊的,因此,它应该在使用时被标记。 (标记using
声明是不正确的; 10.2(1)明确指出名称的模糊用法在查找时被标记,而不是在声明上。)
将这个程序与类似的程序进行对比很有意思,它是a recognized gcc bug的主题(稍微修改了该错误报告以使并行更清晰):
#include <iostream>
struct A {
static int foo() {return 1;}
static int foo(char) { return 2;}
};
struct B1 : A {
// using A::foo;
};
struct B2 : A {
// using A::foo;
};
struct C : B1, B2 {
// using B1::foo;
// using B2::foo;
};
int main()
{
std::cout << C::foo();
}
以上程序是正确的;尽管有钻石继承,foo
是A
的静态成员,所以它并不含糊。事实上,gcc编译它没有问题。但是,取消注释using A::foo
的两个实例(不会改变foo
的任何内容)会导致gcc产生错误报告中记录的奇怪重复错误。取消注释using
中的两个C
声明,这可能会触发此问题主题的另一个错误,然后屏蔽static function
错误并导致程序再次编译。
clang似乎处理了该程序的所有可能变体,因为它的价值。
最后请注意,foo(bool)
(原始计划中)中明确声明的C
将胜过foo(bool)
C
范围内的using
using
1}}声明。我怀疑这两个错误都是由于记账不良造成的,同时试图跟踪每个类范围内的各种函数声明及其个别出处(作为{{1}}声明和函数声明的序列)。