Класс шаблона не видит унаследованный член шаблона - PullRequest
0 голосов
/ 24 июня 2018

Позвольте мне рассмотреть шаблонный класс, который является производным от базового шаблонного класса. Базовый класс содержит член шаблона. В этом случае обычно члены базового класса могут быть доступны из производного класса с помощью указателя this. Однако, похоже, что это не тот случай, когда базовый элемент сам является функцией шаблона.

Рассмотрим следующий код

#include <iostream>

template <class T>
struct base {
  T x;
  base() { x = 10; }
  template <unsigned int N>
  void increment() { x += N; }
};

template <class T>
struct deriv : public base<T> {
  using base<T>::base;

  void p()
  {
    using namespace std;
    cout << this->x << endl;
    base<int>::increment<1>();
    // The following statement causes the compile error:
    // expected primary-expression before ‘)’ token
    // this->increment<1>();
    // Also the following statement gives error
    // base<T>::increment<1>();
    cout << this->x << endl;
  }
};

int main()
{
  using namespace std;

  base<int> A;
  cout << A.x << endl;
  A.increment<1>();
  cout << A.x << endl;

  deriv<int> B;
  B.p();

  return 0;
}

В подпрограмме main элемент шаблона increment вызывается из переменной типа base. Это работает без проблем. С другой стороны, функция-член p() класса deriv пытается получить доступ к шаблонной функции increment, унаследованной от базы. Используя указатель this как в закомментированной строке выше

this->increment<1>();

выдает ошибку компиляции

expected primary-expression before ‘)’ token

Попробовав некоторое время, я обнаружил, что, как и в приведенном выше коде, возможно получить доступ к функции increment через оператор области действия

base<int>::increment<1>();

Это, однако, явно создает base с T=int. Если я хочу вызвать increment член из унаследованного base<T>, с общим T классом как

base<T>::increment<1>();

Я получаю ту же ошибку, что и выше.

Я использую gcc 8.1.1

Вопрос в том, почему при использовании указателя this компилятор не может разрешить унаследованную функцию-член increment? Как я могу получить экземпляр унаследованной функции шаблона increment из унаследованного класса base?

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

Редактировать: небольшая коррекция в программе, тот же вопрос.

Ответы [ 2 ]

0 голосов
/ 24 июня 2018

Если не указано иное, компилятор предполагает, что имя, к которому вы обращаетесь, не является шаблоном, поэтому оба символа < и > маркируются как знаки меньше и больше соответственно (строка анализируется как ((this->increment)<1)>()),Это происходит потому, что this и base<T> зависят от параметра шаблона T, и компилятор не может найти increment, чтобы определить, является ли он шаблоном.Это относится к любому случаю, когда имя слева от оператора зависит от любого параметра шаблона, а имя справа - идентификатор шаблона (имя с <>).Чтобы решить эту проблему, вам нужно использовать ключевое слово template

base<T>::template increment<1>();
this->template increment<1>();

Почему тогда компилируется base<int>::increment<1>();?Поскольку оно не зависит от T (относится к известной специализации), таким образом, можно найти имя increment, чтобы определить, является ли оно шаблоном или нет.
Но оно не скомпилируется, если T не int.gcc выдает следующую ошибку
[x86-64 gcc 8.1 #1] error: type 'base<int>' is not a base type for type 'deriv<long long int>'
Если бы base<int>::increment была общедоступной статической, код всегда компилировался (не совсем потому, что компилятор скомпилировал бы, что x не статичен, но с дополнительными изменениями это сделало бы).

0 голосов
/ 24 июня 2018

Вызов this->increment<1>() недопустим, потому что increment является шаблоном зависимой функции.Поэтому вам необходимо использовать ключевое слово template:

this->template increment<1>();

Ваша директива using и вызов base<int>::increment<1>() также неверны.Если deriv создан с типом, отличным от int, ни один из них не будет работать.Вы должны использовать T вместо int в обоих случаях.При этом вызов base<T>::increment<1>() станет недействительным по той же причине, что this->increment<1>() недействителен.Вам также нужно ключевое слово template:

base<T>::template increment<1>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...