Подтвердить что ты не робот

Требуется ли указать аргумент шаблона базового класса, если базовый класс является типом параметра функции-члена?

Следующий код принят VС++ 2013, но отклонен clang 3.4.

Какой компилятор прав в соответствии со стандартом С++?

template<class T>
struct A
{
    T n;
};

template<class T>
struct B : A<T>
{
    // VC++ 2013 : OK
    // clang : error : use of class template 'A' requires template arguments
    B& f1(const A& obj) 
    {
        return *this;
    }

    // VC++ : OK
    // clang : OK
    B& f2(const A<T>& obj)
    {
        return *this;
    }
};

int main()
{
    B<int> b;
}
4b9b3361

Ответ 1

Мой первый инстинкт - сказать, что VС++ прав в этом. Поиск имени A в B должен найти inted-class-name A внутри A<T>, который также может использоваться как имя типа для ссылки на A<T>.

С++ 11 [temp.local]:

1 Подобно нормальным (не шаблонным) классам, шаблоны классов имеют введенное имя класса (раздел 9). Имя введенного класса может использоваться как имя шаблона или имя типа. Когда он используется с шаблоном-аргументом-списком, в качестве аргумента-шаблона для шаблона-шаблона шаблона или в качестве конечного идентификатора в специфицированном спецификаторе типа объявления шаблона класса друга, оно относится к самому шаблону класса. В противном случае это эквивалентно к имени шаблона, за которым следуют шаблонные параметры шаблона класса, заключенного в <>.

2...

3 Введенное имя класса шаблона класса или специализации шаблона шаблона можно использовать либо как имя шаблона или имя типа, где бы оно ни находилось. [Пример:

template <class T> struct Base {
  Base* p;
};

template <class T> struct Derived: public Base<T> {
  typename Derived::Base* p; // meaning Derived::Base<T>
};

Однако в то же время [temp.dep] §3 гласит:

3 В определении шаблона класса или класса, если базовый класс зависит от шаблона-параметра, базовый класс область не рассматривается при поиске неквалифицированного имени либо в точке определения шаблона класса или член или во время создания шаблона или члена класса.

Исходя из этого, я бы более склонен сказать, что clang на самом деле прав, поскольку имя введенного класса A находится внутри области A<T>, которая зависит от параметра шаблона B T и, таким образом, не выполняется поиск при неквалифицированном поиске имени. Вторичными доказательствами для этого было бы то, что в примере из [temp.local] вместо Base используется Derived::Base.

Итак, я бы сказал, что

  • это хороший угловой регистр, а

  • clang на самом деле прав, чтобы не исследовать область действия A<T>

Ответ 2

Клэнг правильный; хотя имя класса с введенным классом A, безусловно, видимо внутри A<T> и поэтому видимо в производном классе B<T>, это зависимое имя, поэтому область базового класса не рассматривается в B<T>.

Поиск видимости базового класса зависимого имени обсуждается в 14.6.2p3:

В определении шаблона класса или класса, если базовый класс зависит от параметра шаблона, область базового класса не рассматривается при поиске неквалифицированного имени либо в точке определения шаблона или члена класса, либо во время создание шаблона или члена класса.