Russian Qt Forum
Апрель 30, 2024, 18:05 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: Специализация шаблона для базового класса  (Прочитано 22831 раз)
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #30 : Сентябрь 20, 2016, 22:11 »

Попробовал вариант с хелпером... появилась такая проблема: допустим, у нас классы

class A;
class B;
class B1: public B;
class B2: public B;

template<>
class T<A>;

template<>
class T<B>;

Теперь, мне нужно инстанциировать все возможные T<B1>, T<B2>, и т.д.
Но компилятор говорит, что "нету специализаций для B1 и B2".
Это странно, т.к. я явно указал T<B> для базового класса. По идее, такие же правила должны действовать и для наследников Непонимающий
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
m_ax
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2094



Просмотр профиля
« Ответ #31 : Сентябрь 20, 2016, 23:17 »

Нет, T<B> и T<B1> - это разные типы с точки зрения языка..
Записан

Над водой луна двурога. Сяду выпью за Ван Гога. Хорошо, что кот не пьет, Он и так меня поймет..

Arch Linux Plasma 5
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #32 : Сентябрь 20, 2016, 23:42 »

Нет, T<B> и T<B1> - это разные типы с точки зрения языка..

Это довольно странно, ведь налицо возможность "статической виртуализации".
Для компилятора в принципе здесь нет проблемы неоднозначности.
Он видит, что для B1 нет специализации, идет вверх по иерархии, находит B и генерирует код...
По крайней мере так было бы логично, имхо.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #33 : Сентябрь 21, 2016, 13:26 »

...
Теперь, мне нужно инстанциировать все возможные T<B1>, T<B2>, и т.д.
Но компилятор говорит, что "нету специализаций для B1 и B2".
Это странно, т.к. я явно указал T<B> для базового класса. По идее, такие же правила должны действовать и для наследников Непонимающий

Код
C++ (Qt)
struct A{ void print(){cout << "A" << endl;} };
struct B{ void print(){cout << "B" << endl;} };
struct B1: public B{ void print(){cout << "B1" << endl;} };
struct B2: public B{ void print(){cout << "B2" << endl;} };
 
template< class U, typename E = void >
struct T
{ void print(){cout << "T<U>" << endl;} };
 
template<>
struct T<A>
{ void print(){cout << "T<A>" << endl;} };
 
template<class U>
struct T<U, typename enable_if<is_base_of<B, U>::value>::type>
{ void print(){cout << "T<B>" << endl;} };
 
int main()
{
   T<A> t_a;
   T<B> t_b;
   T<B1> t_b1;
   T<B2> t_b2;
 
   t_a.print();
   t_b.print();
   t_b1.print();
   t_b2.print();
 
   return 0;
}
 

Но если уровней наследования больше, то какую специализацию использовать?

Код
C++ (Qt)
struct A{ void print(){cout << "A" << endl;} };
struct B{ void print(){cout << "B" << endl;} };
struct B1: public B{ void print(){cout << "B1" << endl;} };
struct B2: public B{ void print(){cout << "B2" << endl;} };
struct B21: public B2{ void print(){cout << "B21" << endl;} };
 
template< class U, typename E = void >
struct T
{ void print(){cout << "T<U>" << endl;} };
 
template<>
struct T<A>
{ void print(){cout << "T<A>" << endl;} };
 
template<class U>
struct T<U, typename enable_if<is_base_of<B, U>::value>::type>
{ void print(){cout << "T<B>" << endl;} };
 
template<class U>
struct T<U, typename enable_if<is_base_of<B2, U>::value>::type>
{ void print(){cout << "T<B2>" << endl;} };
 
int main()
{
   T<A> t_a;
   T<B> t_b;
   T<B1> t_b1;
   T<B2> t_b2;
   T<B21> t_b21;
 
   t_a.print();
   t_b.print();
   t_b1.print();
   t_b2.print();
   t_b21.print();
 
   return 0;
}
 
Записан

Пока сам не сделаешь...
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #34 : Сентябрь 21, 2016, 15:01 »

Цитировать
Но если уровней наследования больше, то какую специализацию использовать?

Ту, для которой специализирован ближайший предок.
то есть для B21 это будет B2.
Для В1 будет В.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #35 : Сентябрь 21, 2016, 15:33 »

Ту, для которой специализирован ближайший предок.
то есть для B21 это будет B2.
Для В1 будет В.

Это в данном частном случае вы так решили Улыбающийся. Но в общем случае компилятору что делать? В С++ поддерживается множественное наследование, не всегда всё сводится к простым случаям "первый ближайший предок". И определить этого первого ближайшего предка, похоже, не так просто. В std type_traits я такого не встречал. Гуглить "c++ primary|direct base class trait".
Записан

Пока сам не сделаешь...
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #36 : Сентябрь 21, 2016, 15:49 »

Основная идея (проблема) в следующем.
Есть закрытая гуй-библиотека, которая содержит разные графические классы.
Некоторые из них имеют общего предка, некоторые нет.
У меня задача расширить функциональность всех этих классов одинаковым образом.
В настоящее время это сделано так, что параллельно к библиотечным существуют "свои" расширяющие классы.
Для того, чтого они могли сосуществовать с гуй-системой, они обязаны быть наследниками библиотечных объектов.
Решено это с помощью multiple inheritance: "свои" классы наследуются от "расширителей" и от гуй-объектов одновременно.
Т.е. так:

// это гуй-библиотека
class GuiBase;
class GuiObjectA : public GuiBase;
class GuiObjectB : public GuiObjectB;
class GuiObjectC : public GuiBase;
---

// это наши "расширители"
class ItemBase;
class ExtItem1: public ItemBase;
class ExtItem2: public ItemBase;
---

// это "расширенные" гуй-классы (идея)
class GuiItemA:  public GuiObjectA, public ExtItem1;
class GuiItemB:  public GuiObjectB, public ExtItem1;
class GuiItemA2:  public GuiObjectA, public ExtItem2;
class GuiItemC2:  public GuiObjectC, public ExtItem2;
и т.д.
До этого момента примерно понятно. Есть классы унаследованные от разных базовых (от своих +  из либы 1 + из либы 2)

проблема в том, что "расширители" должны иметь доступ к гуи-объектам (что при идее выше не будет работать).
Поэтому был слелан соответсвующий темлейт типа

template <class Gui, class Extender>
class GuiItem: public Gui, public Extender
// тут общий функционал, связывающий Gui и Extender

и далее

class GuiItemA:  public GuiItem<GuiObjectA, ExtItem1>;
class GuiItemC2:  public GuiItem<GuiObjectC, ExtItem2>;
...

в некоторых случаях имплементации GuiItem требуется различать между GuiObjectA и GuiObjectC.
Решено с помощью рантайма, хотя мне казалось, что тут как раз шаблоны - самое оно. Но как-то не срастается...
А тут как-то не очень, "нить теряется"

У меня задача расширить функциональность всех этих классов одинаковым образом.
Можно пример класса и метода что Вы хотите получить?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #37 : Сентябрь 21, 2016, 16:26 »

Но в общем случае компилятору что делать? В С++ поддерживается множественное наследование, не всегда всё сводится к простым случаям "первый ближайший предок". И определить этого первого ближайшего предка, похоже, не так просто.

А тут и не надо ничего решать. Достаточно следовать тем же правилам, которые используются при dynamic_cast.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #38 : Сентябрь 21, 2016, 16:41 »

Цитировать
Можно пример класса и метода что Вы хотите получить?

class A;
class B: public A;
class B1: public B;

template<class A>
class T
{
...
stuff();  // A::stuff();
...
}

template<>
class T<A>
{
stuff();  // вызвать A::stuff
}

template<>
class T<B>
{
stuff();  // вызвать B::stuff
}

А теперь хотим так:

class C: public T<B1>
{
stuff();  // поскольку B1 наследник от В, то вызвать B::stuff - но не работает, ибо "нет специализации для В1"
}
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #39 : Сентябрь 21, 2016, 17:41 »

А тут и не надо ничего решать. Достаточно следовать тем же правилам, которые используются при dynamic_cast.

Я тоже много всего хочу от С++ Улыбающийся.

Код
C++ (Qt)
class A;
class B;
 
class C : public A, public B;
class D: public C;
 
template<class U>
class T;
 
template<>
class T<A>;
 
template<>
class T<B>;
 
T<D> - ???
 

Что компилятору делать в этом случае? Даже в случае с dynamic_cast, к чему приводить будете? Наверняка тут и других особенностей хватает. Это вам в конкретном случае понадобилась специализация по первому предку. А другим в общем случае может не нужно такое поведение, и необходимо, чтобы использовалось общее определение шаблона. Как им тогда указывать, что нужно использовать общее определение, а не специализацию по первому предку?

Буквально на днях была статья на хабре в тему: Наследование реализаций: закопайте стюардессу.

Когда приходится городить такое количество костылей, то проблема, скорей всего, лежит уровнем выше, в архитектуре. Понятно, что принимать стороннюю библиотеку приходится так, как она есть. И если ставится задача расширять коров с помощью коней, то без извращений не обойтись Улыбающийся.
Записан

Пока сам не сделаешь...
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #40 : Сентябрь 21, 2016, 18:23 »

Цитировать
Что компилятору делать в этом случае? Даже в случае с dynamic_cast, к чему приводить будете?

Ну тут все очевидно.
Если воспользоваться принципом dynamic_cast, получим такое:

T<D> d;

if (dynamic_cast<A*>(&d))
{
  // первая специализация - А - совпала ? тогда мы А Улыбающийся
}
else if (dynamic_cast<B*>(&d))
{
  // а тут мы В
}
else
{
  // а тут ни А, ни В
}

Т.е. первая подходящая специализация, для D - это А, что соответствует порядку наследования.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
ViTech
Гипер активный житель
*****
Offline Offline

Сообщений: 858



Просмотр профиля
« Ответ #41 : Сентябрь 21, 2016, 18:48 »

if (dynamic_cast<A*>(&d))
{
  // первая специализация - А - совпала ? тогда мы А Улыбающийся
}
else if (dynamic_cast<B*>(&d))
{
  // а тут мы В
}
else
{
  // а тут ни А, ни В
}

Чем родитель "B" хуже родителя "A"? Улыбающийся Но это лирика.

Можно попробовать вести параллельную иерархию с T:
Код
C++ (Qt)
struct A{ void print(){cout << "A" << endl;} };
struct B{ void print(){cout << "B" << endl;} };
struct B1: public B{ void print(){cout << "B1" << endl;} };
struct B2: public B{ void print(){cout << "B2" << endl;} };
struct B21: public B2{ void print(){cout << "B21" << endl;} };
 
template< class U, typename E = void >
struct T
{ void print(){cout << "T<U>" << endl;} };
 
template<>
struct T<A>
{ void print(){cout << "T<A>" << endl;} };
 
template<class U>
struct T<U, typename enable_if<is_base_of<B, U>::value>::type>
{ void print(){cout << "T<B>" << endl;} };
 
template<>
struct T<B2>
{ void print(){cout << "T<B2>" << endl;} };
 
template<>
struct T<B21> : public T<B2>{};
 
int main()
{
   T<A> t_a;
   T<B> t_b;
   T<B1> t_b1;
   T<B2> t_b2;
   T<B21> t_b21;
 
   t_a.print();
   t_b.print();
   t_b1.print();
   t_b2.print();
   t_b21.print();
 
   return 0;
}
 
Записан

Пока сам не сделаешь...
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #42 : Сентябрь 21, 2016, 20:42 »

Цитировать
Чем родитель "B" хуже родителя "A"?

Порядком наследования. Было бы
Код:
class C: public B, public A
то выигрывал бы В.

Цитировать
Можно попробовать вести параллельную иерархию с T:

Можно, но проблема в том, что не-темплейтные классы может создавать пользователь, а он понятия не имеет об иерархии T Грустный
поэтому мы и не можем специфицировать каждый наследник в отдельности...
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #43 : Сентябрь 22, 2016, 08:42 »

Не въезжаю
template<class A>
class T
{
...
stuff();  // A::stuff();
...
}
Как зовется stuff? Ведь T не наследник аргумента A

template<>
class T<A>
{
stuff();  // вызвать A::stuff
}
Зачем специализация, чем не устраивал общий шаблон?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #44 : Сентябрь 22, 2016, 11:26 »

Извиняюсь, немного ошибся, должно быть так:

Код:
template<class A>
class T: public A
{
...
stuff();  // A::stuff();
...
}

Т.е. создаем наследника от А.
Специализация нужна для того, что не все А имеют одинаковые методы.
Например, для А надо вызвать A::stuff(), а для C надо и С::stuff(), и С::someAnotherStuff():

class C: public B
{
virtual void stuff();
virtual void someAnotherStuff();
};

Шаблон про someAnotherStuff() не знает, т.к. нет возможности проверить, что есть C при инстанциировании T<C>.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.183 секунд. Запросов: 22.