специализировать член шаблона в производном классе - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть базовый класс с членом шаблона, который в некоторых случаях явно специализирован. Производный класс дополнительно специализирует член шаблона базового класса. Смысл этого заключается в том, что различные специализации члена шаблона «логически» выполняют одну и ту же работу, адаптируясь к конкретной ситуации. Базовый класс предоставляет некоторые шаблонные специализации, которые выполняют задачу в некоторых случаях, производный класс должен «распространить» ту же задачу на другие случаи, дополнительно специализируя член шаблона.

Вот минимальный пример, иллюстрирующий проблемы, с которыми я сталкиваюсь.

#include <iostream>

struct A {
  template <int i>
  void dosomething();

  void show();
};

template<>
void A::dosomething<0>()
{
  std::cout << "0 in A" << std::endl;
}

void A::show()
{
  dosomething<0>();
}

struct B : A {
  // Without the following declaration:
  // error: template-id ‘dosomething<1>’ for ‘void B::dosomething()’
  // does not match any template declaration
  template <int i>
  void dosomething();
};

template<>
void B::dosomething<1>()
{
  std::cout << "1 in B" << std::endl;
}

int main()
{
  A x;
  x.dosomething<0>();

  B y;
  y.dosomething<0>(); // Link error!
  y.show();
  y.dosomething<1>();

  return 0;
}

Член шаблона A::dosomething() явно специализирован для i=0 в базовом классе. Код для шаблона генерируется в явном виде и вызывается в элементе A::show().

Первая проблема, которую я обнаружил:

А) Без дублированного объявления

template <int i>
void dosomething();

внутри определения B, код не компилируется, с ошибкой:

template-id ‘dosomething<1>’ for ‘void B::dosomething()’
does not match any template declaration.

Почему предыдущее объявление в базовом классе A не отображается?

B) Приведенный выше код вызывает ошибку связи:

undefined reference to `void B::dosomething<0>()'

Ошибка из-за вызова y.dosomething<0>() в основном. Этого можно избежать, позвонив вместо этого y.A::dosomething<0>(). Почему dosomething<0>() явно невидимо в случае B?

1 Ответ

0 голосов
/ 06 ноября 2018

Когда вы делаете out-of-line определение функции-члена, объявление этой функции ищется в классе, который указан перед оператором ::.

Учтите это:

struct C { void test(); };
struct D : C { };

void D::test() { }; // error, test is not a member of D but of C

это то же самое, что и

template<> void B::dosomething<1>() 
{ }

dosomething и все определения специализации должны быть квалифицированы классом, в котором он был объявлен, т. Е. В A, как вы это сделали с dosomething<0>.

Также обратите внимание, что объявление dosomething в B совершенно не связано с объявлением A. вы получаете ошибку ссылки из-за вызова не определенной специализации B::dosomething<0>.

Вы можете создать специализацию template<> void A::dosomething<1>(){ }, но вы не получаете ожидаемое полиморфное поведение, A::dosomething<1> будет использоваться всеми производными классами, если вам действительно нужны разные версии dosomething<1> для подклассов. вы ограничены начальным повторением, и для доступа к A::dosomething<0> из B вы делаете это как static_cast<A&>(b).dosomething<0>().

Вы также должны взглянуть на статический полиморфизм в этом ответе

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...