Инициализация шаблонных типов элемента базового класса в списках инициализатора производного класса

Вот некоторый код, обрисовывающий в общих чертах проблему, с которой я боролся. Заключительная проблема (что касается g ++ в данный момент) состоит в том что: "ошибка: 'Нога' не была объявлена в этом объеме" при выполнении Панели:: Панель (...) стандартная программа конструктора. Иначе проблемой, я пытаюсь изучить свой путь через, является одна из установки типов элемента базового класса на основе аргументов, переданных шаблонам использования конструктора производного класса. Если бы был способ установить тип элемента базового класса (T Нога) просто передающими аргументами конструктору производного класса, то я предпочел бы это. На данный момент я не вижу путь прошлое использование и аргумент шаблона и аргумент конструктора производного класса соответствия для выполнения этой задачи. Можно ли определить что-нибудь в следующем коде, что я могу добиваться большего успеха для достижения тех же целей? Я довольно плохо знаком с универсальным кодированием и шаблонами.

#include <iostream>
typedef int a_arg_t;
typedef double b_arg_t;
typedef std::string foo_arg_t;

class TypeA {
public:
    TypeA ();
    TypeA (a_arg_t a) {
        /* Do sosmething with the parameter passed in */
    }

};

class TypeB {
public:
    TypeB ();
    TypeB (b_arg_t b) {
        /* typeB's constructor - do something here */
    }

};

// The base-class with a member-type to be determined by the template argument
template <class T>
class Foo {

public:
    Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg)       // initialize something here
    {
        /* do something for foo */
    }
    T Foo_T;        // either a TypeA or a TypeB - TBD
    foo_arg_t _foo_arg;
};

// the derived class that should set the basse-member type (T Foo_T)
template <class T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {
        // the initialization of Foo_T has to be done outside the initializer list because it's not in scsope until here
        Foo_T = TypeA(a_arg);   // if an a_arg_t is passed in, then we set the Foo_T to TypeA, etc.
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo_T = TypeB(b_arg);
    }

};

int main () {

    b_arg_t b_arg;
    a_arg_t a_arg;
    foo_arg_t bar_arg;

    Bar<TypeA> a (bar_arg, a_arg);  // try creating the derived class using TypeA
    Bar<TypeB> b (bar_arg, b_arg); // and another type for show

return 0;
}
15
задан Kris 28 November 2019 в 00:03
поделиться

3 ответа

The Foo_T type will not be looked up in the base class when used in the derived (Bar) constructor.

Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg)   // base-class initializer
{
    Foo_T = TypeA(a_arg);   TypeA, etc. // Won't compile, per the standard
}

This is per the C++ standard, which says unqualified names are generally non-dependent, and should be looked up when the template is fully defined.

Since a template base class definition is not known at that time (there could be fully specialised instances of the template being pulled in later in the compilation unit), unqualified names are never resolved to names in dependent base classes.

If you need a name from a base class when templates are involved, you have to either fully qualify them, or make them implicitly dependent in your derived class.

 Foo< T >::Foo_T = TypeA(a_arg);   // fully qualified will compile

or, make it dependent

 this->Foo_T = TypeA(a_arg);

Since the this makes it template dependent, resolving the type is postponed till "phase 2" of template instantiation (and then, the base class is also fully known)

Note that if you wanted to use a function from the base class, you could have also added a using declaration..

(inside Bar())

  some_foo_func(); // wouldn't work either

  using Foo<T>::some_foo_func;
  some_foo_func(); // would work however
17
ответ дан 1 December 2019 в 03:43
поделиться

Извините за бесполезность, но я также не вижу способа обойти это, если не сделаю в точности то, что вы заявили:

На данный момент я не вижу выхода из употребления как аргумент шаблона, так и соответствующий конструктор производного класса аргумент для выполнения этой задачи.

Вероятно, вам придется немного специализироваться:

template<>
Bar<TypeA>::Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<TypeA>(bar_arg)   // base-class initializer
{
    // the initialization of Foo_T has to be done outside the initializer list because it's not in scsope until here
    Foo_T = TypeA(a_arg);   // if an a_arg_t is passed in, then we set the Foo_T to TypeA, etc.
}

template< class T>
Bar<T>::Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
: Foo<T>(bar_arg)   // base-class initializer
{
    // Throw exception?
}

template<>
Bar<TypeB>::Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<TypeB>(bar_arg)
{
    Foo_T = TypeB(b_arg);
}

template< class T >
Bar<T>::Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
: Foo<T>(bar_arg)
{
    // Throw exception ?
}

К сожалению, в настоящий момент у меня нет доступа к компилятору, чтобы проверить этот код, так что будьте осторожны.


В ответ на ваш вопрос /комментарий. Мне нужно скомпилировать следующее:

#include <iostream>
typedef int a_arg_t;
typedef double b_arg_t;
typedef std::string foo_arg_t;

class TypeA {
public:
  TypeA () {}
  TypeA (a_arg_t a) {}
};

class TypeB {
public:
  TypeB () {}
  TypeB (b_arg_t b) {}
};

template <class T>
class Foo {
public:
  Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg) {}
  T Foo_T;        // either a TypeA or a TypeB - TBD
  foo_arg_t _foo_arg;
};

// the derived class that should set the basse-member type (T Foo_T)
template <class T>
class Bar : public Foo<T> {
public:
  Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
  : Foo<T>(bar_arg)   // base-class initializer
  {
    Foo<T>::Foo_T = TypeA(a_arg);
  }

  Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
  : Foo<T>(bar_arg)
  {
    Foo<T>::Foo_T = TypeB(b_arg);
  }
};

int main () {
  b_arg_t b_arg;
  a_arg_t a_arg;
  foo_arg_t bar_arg;

  Bar<TypeA> a (bar_arg, a_arg);  // try creating the derived class using TypeA
  Bar<TypeB> b (bar_arg, b_arg); // and another type for show

  return 0;
}
3
ответ дан 1 December 2019 в 03:43
поделиться

Когда я впервые взглянул на ваш код, я был абсолютно уверен, что вам придется решать проблему частичной специализацией. На самом деле, это все еще может быть так, однако я уменьшил количество кода, необходимого для репликации вашей ошибки, и заметил, что ошибка возникает только при компиляции с помощью gcc (я не знаю, какая версия компилятора работает в моем университете, хотя ), а при компиляции с Visual Studio 2003 - все довольны.

Следующий код повторяет код ошибки, но незначительное, казалось бы, невинное изменение неожиданно устранит его:

template <typename T>
class ClassA
{
public:
    ClassA () {}
    T vA;
};


template<typename T>
class ClassB : public ClassA<T>
{
public:
    ClassB ()
    {
        vA = 6;
    }
};

int main ()
{
    ClassB<int> cb;
}

Теперь, если вы удалите объявление шаблона из ClassB, и напрямую наследовать от ClassA:

class ClassB : public ClassA<int>
{
public:
    ClassB ()
    {
        vA = 6;
    }
};

, а затем изменить объявление cb на соответствие

    ClassB cb;

. Затем ошибка исчезнет,

0
ответ дан 1 December 2019 в 03:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: