Я был удивлен тем фактом, что 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);
}
Вышеупомянутый вызов функции компилируется и возвращается true
на GCC 4.7.2 и GCC 4.8.0 (бета), в то время как не скомпилируется (как я и ожидал) на Clang 3.2 и ICC 13.0.1.
Это случай «Диагностика не требуется«или это ошибка в GCC? Ссылки на стандарт C ++ 11 приветствуются.
§7.3.3 / 3:
В объявлении использования, используемом в качестве объявления члена, спецификатор вложенного имени должен называть базовый класс определяемого класса. Если такое объявление-использование называет конструктор, спецификатор nested-name-name должен называть прямой базовый класс определяемого класса; иначе он вводит набор объявлений, найденных при поиске имени члена (10.2, 3.4.3.1).
¶14:
… [Примечание: два объявления-использования могут представлять функции с одинаковыми именами и одинаковыми типами параметров. Если для вызова неквалифицированного имени функции разрешение перегрузки функции выбирает функции, представленные такими объявлениями использования, вызов функции некорректен.
¶16:
В целях разрешения перегрузки функции, которые вводятся объявлением использования в
Производный класс будет обрабатываться так, как если бы он был членом производного класса.
Итак using
декларации являются допустимыми, но функции являются одноранговыми в том же наборе перегрузки, как вы сказали, и программа некорректна.
Призыв к foo(true)
в вашей программе, как вы говорите, явно неоднозначно; кроме того, он является неоднозначным в соответствии с алгоритмом, представленным в §10.2, и, следовательно, он должен быть помечен при использовании. (Пометка using
декларация будет неправильной; 10.2 (1) четко заявляет, что неоднозначное использование имен помечается при поиске, а не при объявлении.)
Интересно сравнить эту программу с аналогичной, которая является предметом признанная ошибка gcc (немного изменен из отчета об ошибке, чтобы сделать параллель более понятной):
#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
объявления и объявления функций).