Шаблоны и динамический полиморфизм
От: x-code  
Дата: 12.08.15 18:49
Оценка:
Такая задача. Допустим, есть базовый интерфейс Base с чистыми виртуальными функциями, от него куча наследников.
Допустим, есть некая шаблонная функция (одна из многих специализаций). Например такая:
template<typename T>
void foo(std::vector<T*> &v)
{
  size_t n = v.size();
  for(size_t i=0; i<n; i++)
    bar(v[i]);
}


здесь bar — тоже шаблонная функция, возможно это та же функция foo() или какая-то обертка (смысл в том что с помощью этих шаблонных функций осуществляется рекурсивный обход сложной древовидной структуры, связи которой основаны на указателях Base*)

Проблема в следующем. Типом T может быть некоторый тип в иерархии (Base или какой-то наследник), а реальными элементами вектора могут быть указатели на любые наследники этого типа, разные в разных элементах вектора. Нужно вызвать foo<>() для настоящего типа (который в рантайме), а не для того который виден статически на этапе компиляции.

В качестве решения можно ввести в интерфейс Base и в каждый класс-наследник некую специальную виртуальную функцию, единственная задача которой — вызвать foo<>() для своего аргумента this. То есть из шаблона осуществляется некий вызов, класс определяется только в рантайме, вызывается функция-переходник нужного класса-наследника, из которой вызывается foo<>() — уже статически, с нужным типом. То есть вместо bar() будет что-то вроде v[i]->visit();

Но тут возникает несколько неприятных технических вещей. Система шаблонов сплетается с иерархией классов в единое целое, а хотелось бы оставить их независимыми. Если иерархия классов видима из системы шаблонов, то наоборот — нет, и крайне не хотелось бы сливать все в один заголовочный файл. Нужно обеспечить видимость foo<>() везде, где она вызывается (на самом деле это единственный файл с макросом, который уже вставлен в каждый класс-наследник Base). Прототип шаблонной функции foo<>() объявленный перед интерфейсом Base не помогает, компилятор не воспринимает его как прототип... наверное это и правильно, ведь на самом деле там несколько десятков реализаций.

Нет ли каких-то стандартных решений для исходной задачи?
Re: Шаблоны и динамический полиморфизм
От: Caracrist https://1pwd.org/
Дата: 12.08.15 20:24
Оценка: +1
Здравствуйте, x-code, Вы писали:

почему v[i]->visit(); не угодил?

struct Base1 { virtual void visit() = 0; };
struct Base2 { virtual void visit() = 0; };
struct Derrived1 : Base1 { virtual void visit() {} };
struct Derrived2 : Base2 { virtual void visit() {} };

vector<Base1*> vec1 = {new Derrived1()};
vector<Base2*> vec2 = {new Derrived2()};
foo(vec1);
foo(vec2);


~~~~~
~lol~~
~~~ Single Password Solution
Re[2]: Шаблоны и динамический полиморфизм
От: x-code  
Дата: 12.08.15 21:31
Оценка:
Здравствуйте, Caracrist, Вы писали:

C>почему v[i]->visit(); не угодил?


Там код более универсальный, чем класс Base и любые его наследники.
Функция foo<>() обрабатывает не только иерархию Base, но и все простые типы, многие stl-типы, некоторые не входящие в иерархию Base составные типы, а также любые структурные типы, для которых определены внешние функции обработки.

Например, внутри объекта Derived1 могут быть поля int, float, std::string, сишные массивы из этих типов, несколько указателей на классы иерархии Base, несколько массивов таких указателей, несколько объектов и указателей на объекты специальных типов, не входящих в иерархию Base, и т.д. Для каждого поля вызывается своя версия шаблонной функции, причем это делается почти автоматически, через хитрую систему макросов.

Поэтому v[i]->visit() должна каким-то образом опять вызвать foo<>() уже для this == v[i], чтобы универсально обработать все внутренние поля v[i].

А просто вызвать я ее не могу, возникают циклические инклуды.
Re[3]: Шаблоны и динамический полиморфизм
От: VTT http://vtt.to
Дата: 13.08.15 07:59
Оценка:
Здравствуйте, x-code, Вы писали:

XC>через хитрую систему макросов.


Вы там не перемудрили случаем?

XC>Поэтому v[i]->visit() должна каким-то образом опять вызвать foo<>() уже для this == v[i], чтобы универсально обработать все внутренние поля v[i].


А зачем вам вызывать foo<>() уже для this == v[i]? Вызывайте foo<>() внутри реализации visit этого класса для каждого нужного поля этого класса. Или вы хотите чтобы оно как-то само пробегалось по всем полям? Тогда в foo<>() надо делать соответствующий механизм без инклюдов конкретной реализации класса Base.
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Re: Шаблоны и динамический полиморфизм
От: Кодт Россия  
Дата: 13.08.15 13:23
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Нет ли каких-то стандартных решений для исходной задачи?


Стандартные есть, но не в чистом С++.
Во-первых, partial class из C# и прототипы из ObjC.
Во-вторых, мультиметоды как способ вынести виртуальные функции вовне.

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

Тут вопрос в том, насколько ветвистая и насколько расширяемая иерархия типов и обработчиков.
И с чем связано желание изолировать реализацию:
— слишком долго компилируется
— макаронистый код, жалко отдавать в паблик
— нужно обеспечить дешёвое масштабирование

А то, если типов и обработчиков мало, то пусть все видят всех. Максимум, наколбасить интерфейсов для каждого обработчика и его ответной части.
Перекуём баги на фичи!
Re[2]: Шаблоны и динамический полиморфизм
От: x-code  
Дата: 14.08.15 21:28
Оценка:
Здравствуйте, Кодт, Вы писали:

наверное я все путано объяснил, вы слишком абстрактно ответили

хотя я понимаю что мне нужно, и понимаю что скорее всего задачу не решить, но тут даже сформулировать нормально сложно...
Re: Шаблоны и динамический полиморфизм
От: ollv СССР https://youtu.be/DQDoYs6wHoo
Дата: 17.08.15 02:40
Оценка:
Здравствуйте, x-code, Вы писали:

XC>Нет ли каких-то стандартных решений для исходной задачи?

возможно подойдет список?


static std::map<std::string, std::function<void (boost::any const& )> > handlers;

struct caller 
{
   void call_int(boost::any const &arg)
   {
      std::vector<int> const& v = boost::any_cast<std::vector<int> >(arg);
   }
   
   template<typename T>
   inline void call_any(boost::any const &arg) {
      std::vector<T> const& v = boost::any_cast<std::vector<T> >(arg); 
   }
};

class A { 
  public: 
};

void assign()
{
  handlers["int"] = std::bind(&caller::call_int, caller(), std::placeholder::_1);   
  handlers["A"] = std::bind(&caller::template call_any<A>, caller(), std::placeholder::_1);
}
Compiler can be as trained AI but can't compose music.
Antheil piano jazz sonata. Я болен ПГМ.
Re[3]: Шаблоны и динамический полиморфизм
От: Кодт Россия  
Дата: 17.08.15 09:26
Оценка:
Здравствуйте, x-code, Вы писали:

XC>наверное я все путано объяснил, вы слишком абстрактно ответили


Абстрактный вопрос — абстрактный ответ!

В копилку готовых решений: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_typeerasure.html

XC>хотя я понимаю что мне нужно, и понимаю что скорее всего задачу не решить, но тут даже сформулировать нормально сложно...


А что, если не абстрагировать, не говорить "некие объекты и функция foo", а "вот такого рода объекты и вот с таким именем функция, делающая вот что".
Тогда телепатия будет мощнее.
Перекуём баги на фичи!
Re[4]: Шаблоны и динамический полиморфизм
От: x-code  
Дата: 17.08.15 20:08
Оценка: -1
Здравствуйте, Кодт, Вы писали:

К>А что, если не абстрагировать, не говорить "некие объекты и функция foo", а "вот такого рода объекты и вот с таким именем функция, делающая вот что".


Сделал, хотя и не совсем универсально. Была ошибка, забыл указать namespace в extern-описании шаблонной функции.

Для универсальности нужно было что-то вроде шаблонных виртуальных функций, которые бы создавались в нужном количестве для каждого значения шаблонного аргумента, или не создавались вовсе, если бы никто их не инстанцировал. Но такого, насколько я понимаю, в С++ нет.

Поэтому сейчас, для того чтобы перейти от статического типа к реальному динамическому, я жестко прибил вызов шаблонной функции-обработчика (параметром которой как раз и должен быть реальный динамический тип, а не статический) внутри виртуальной прокладки; а хотелось передать ее шаблонным параметром, чтобы не связывать эти две разные группы кода.
Re[5]: Шаблоны и динамический полиморфизм
От: Кодт Россия  
Дата: 18.08.15 10:09
Оценка:
Здравствуйте, x-code, Вы писали:

<>

Продолжаешь шифроваться от коллег? Ну-ну.
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.