Странное поведение объявления использования

см. следующий код

struct A { using type = int; };
struct B : private A {};
struct C : B { using base_type = A; };

Все gcc 6.1, clang 3.8 и msvc 2015 update 3 отказываются компилировать это, так как A не является доступным именем внутри C, поскольку A является частной базой B. Кажется, gcc считает, что A в using base_type = A относится к конструктору по умолчанию A. msvc и clang вроде нет.

Возможно, ошибка компиляции связана с внедрением имен, вызванных наследованием (поскольку изменение using base_type = A в using base_type = ::A заставляет все компиляторы работать нормально), но я хочу знать, соответствует ли эта странная ошибка тому, что говорит стандарт.

Более конкретно,

  1. Как я понял, в отличие от A::type, A — это просто имя класса (хотя gcc неверно интерпретирует его как имя функции), которое вводится в C не внутри A и B. Почему это имя считается личным для B?
  2. Следует ли считать эту ошибку компиляции ошибкой или это крайний случай спецификаций стандарта?

person Junekey Jeon    schedule 04.07.2016    source источник
comment
Я предполагаю, что это связано с тем, как работает поиск имени для A внутри C. Сначала он проверяет, не объявлено ли что-либо с именем A в области действия C до using. Поскольку он не находит его, он проверяет его в области B, поскольку это базовый класс. И в случае, если он не найдет A в области Bs, он будет искать в области global namespace. Но каким-то образом private inheritance из A по B останавливается при втором поиске, то есть внутри области B. Поскольку он работает с использованием имени fully qualified, это заставляет меня думать, что реальная проблема должна быть в тех же строках.   -  person Arunmu    schedule 04.07.2016
comment
eel.is/c++draft/class.access.spec#5 кажется актуальным   -  person Piotr Skotnicki    schedule 04.07.2016
comment
@PiotrSkotnicki Спасибо, это прямо отвечает на вопрос. Но можете ли вы дать мне обоснование этого правила?   -  person Junekey Jeon    schedule 04.07.2016
comment
@PiotrSkotnicki Ну, все в порядке. Я думаю, что я немного понял вещи. Спасибо!   -  person Junekey Jeon    schedule 04.07.2016


Ответы (2)


Согласно правилу поиска неполного имени:

(выделено мной)

Для неполного имени, то есть имени, которое не появляется справа от оператора разрешения области ::, поиск имени проверяет области, как описано ниже, пока не найдет хотя бы одно объявление любого типа, в котором время поиск останавливается, и дальнейшие области не проверяются.

Таким образом, имя A сначала будет найдено в области видимости базового класса, имя в глобальном пространстве имен здесь рассматриваться не будет. После этого выполняется проверка прав доступа, после чего компиляция не удалась.

А ::A указывает имя в глобальной области видимости и решает проблему, превращая поиск в полный поиск имени.

person songyuanyao    schedule 04.07.2016

Размещение моего комментария в качестве ответа (похоже на ответ больше, чем на комментарий):

Я предполагаю, что это связано с тем, как работает поиск имени для Ainside C. Сначала он проверяет, не объявлено ли что-либо с именем A в области C перед использованием. Поскольку он не находит его, он проверяет его в области B, поскольку это базовый класс. И в случае, если он не найдет A в области B, он будет искать в global namespace. Но каким-то образом частное наследование A на B останавливается при втором поиске, то есть внутри области B. Поскольку он работает с использованием имени fully qualified, это заставляет меня думать, что реальная проблема должна быть в тех же строках.

person Arunmu    schedule 04.07.2016