2016-04-11 2 views
3

Наконец-то мне удалось свернуть мой монолитный отказ библиотеки библиотеки шаблонов до простого тестового примера. MSVC не согласен с Clang и GCC в том, что код неверен, в основном из-за поиска имени. К сожалению, я не умею читать спецификацию на C++, и я склонен верить Clang и GCC, когда дело доходит до соответствия, но не могли бы вы помочь мне найти соответствующую часть спецификаций, чтобы я мог подать ошибку?Поиск имени с классом шаблона, наследующим по пространствам имен

namespace A 
{ 
    template <int _I, int _II> 
    struct X {}; 
} 

namespace B 
{ 
    template <int _J> 
    struct X {}; 

    // Clang: OK 
    // GCC: OK 
    // MSVC: OK 
    template <int _K> 
    struct Y 
    { 
     Y(const A::X<_K, _K>&, 
      const X<_K>&) {} 
    }; 

    // Clang: OK 
    // GCC: OK 
    // MSVC: ERROR 
    template <int _K> 
    struct Z : A::X<_K, _K> 
    { 
     Z(const A::X<_K, _K>&, 
      const X<_K>&) {} 
    }; 

    // Clang: ERROR 
    // GCC: ERROR 
    // MSVC: ERROR 
    struct Q : A::X<1, 1> 
    { 
     Q(const A::X<1, 1>&, 
      const X<1>&) {} 
    }; 
} 

int main() 
{ 
    A::X<1, 1> ax; 
    B::X<1> bx; 

    B::Z<1> bz(ax, bx); 

    return 0; 
} 

три случая:

  1. Y нет ничего необычного. Он компилируется с обоими компиляторами.
  2. Ошибка компиляции связана со вторым аргументом ZOR CT, X, не имеющим достаточных аргументов шаблона. Это зависит от поиска имени, чтобы решить, к какому X я отношусь. Насколько я понял из чтения cppreference, наследование от класса не должно вводить его имя в область, когда дело доходит до поиска неквалифицированного имени.
  3. Если сам класс Q не является шаблоном, все компиляторы отклоняют его. Теперь это та часть, где я полностью теряю почву. Почему имеет значение, является ли класс шаблоном или нет?

Что здесь происходит?

+1

Боковое примечание: здесь вы используете кучу зарезервированных идентификаторов – melak47

ответ

3

Проблема, с которой вы столкнулись, - это имя введенного класса. Из [класса]:

Класс имятакже вставляется в сферу самого класса; это известно как имя введенного класса. Для проверки доступа имя введенного класса рассматривается как имя публичного участника.

С безоговорочным поиском в определении класса первая остановка входит в сферу действия класса и его членов. Из [basic.lookup.unqual]:

имени, используемое в определении класса X внешней функции элемента корпуса, аргумент по умолчанию, исключение-спецификация, скобки или равно-инициализатор из нестатических Элемент данных, или определение, вложенный класс должен быть объявлено в одном из следующих способов:
(7.1) - до ее использования в классе X или быть членом базового класса X (10.2), или
(7.2) - [...]

Мы ищем X. Существует не (Q), но есть A::X<1,1>::X (область базового класса), поэтому поиск останавливается там, и мы никогда не рассматриваем пространство имен в Q. Вот почему мы находим A::X<> вместо B::X<>.

С Z ситуация немного отличается. Теперь базовый класс является зависимым от шаблоном класса, а неквалифицированный поиск не будет выглядеть в зависимых базовых классах. Из [temp.dep]:

В определении шаблона класса или класса, объем зависимого базового класса (14.6.2.1) не рассматривается во имя неквалифицированного поиска либо в точке определения шаблон шаблона или участника или в течение экземпляр шаблона или члена класса.

Таким образом, хотя название A::X<_K,_K>::X существует, то он не считается, поэтому поиск продолжается в пространстве имен объемлющего и B::X<> найден.

В обоих случаях gcc/clang являются правильными.

0

сообщение об ошибке ССАГПЗ предоставляет ключ:

38 : error: wrong number of template arguments (1, should be 2) 
const X<1>&) {} 
^ 
4 : note: provided for 'template<int _I, int _II> struct A::X' 
struct X {}; 
^ 

Что здесь происходит?

Шаблон класса не является кодом. Это рецепт создания кода. двухфазный поиск будет обрабатывать определение Z<>, когда вы его используете (в этот момент лучше было бы иметь X<i>).

Q - это конкретный класс, поэтому нет двухфазного поиска. X<i> должен существовать в этой точке - и это не так.

Как всегда, clang и gcc верны. MSVC не соответствует требованиям.

+1

Вам не понравилось читать сообщение? Я понимаю, что говорит ошибка. Мой вопрос: ПОЧЕМУ он думает, что я имею в виду A :: X? Я говорю X в контексте класса в пространстве имен B, который наследуется от класса в пространстве имен A. Почему X просто ссылается на A :: X, когда неквалифицированный поиск предполагает иное? И почему это имеет значение, если сам класс является шаблоном или нет? – Meteorhead

+0

@Meteorhead изменено. –

+0

Итак, вы говорите, что правило двухфазного поиска подразумевает, что проверка синтаксиса в первом проходе не должна проверять имена функций? Даже если MSVC не «пропустит» первую фазу, оба A :: X и B :: X были проанализированы к тому времени, когда компилятор достигнет Z, поэтому у него есть вся необходимая информация, необходимая для того, чтобы ничего не увидеть. – Meteorhead

Смежные вопросы