C ++ - как преобразовать между типами, которые известны только во время выполнения

Я хочу разработать типобезопасное кросс-соединение NxM. Это механизм, который позволяет подключить любой из N функциональных выходов к любому из M входов. Или, другими словами, связать возвращаемое значение функции (из набора функций) с параметром другого. Ключевым аспектом является то, что эти соединения должны настраиваться во время выполнения. Основная проблема, с которой я столкнулся, заключается в том, что тип входов будет отличаться от выходов в зависимости от каждого соединения.

Скажем, в какой-то произвольный момент в программе я хочу связать возвращаемое значение float foo() с параметром val в void bar(double val).

В настоящее время у меня есть два параметризованных класса, представляющих входы и выходы, с именами Source<T> и Dest<U>. Ожидается, что T & U будет float, double, bool, int, unsigned int и т. Д. У меня есть гетерогенная коллекция из Source<T> экземпляров, некоторые из них double, некоторые float, некоторые int, некоторые bool. Существует также разнородная коллекция Dest<U> экземпляров, а также несколько экземпляров типа double, некоторые с плавающей запятой, некоторые int, некоторые bool. Иногда T и U одного типа. Для большего контекста все эти экземпляры связаны с уникальными именами, что позволяет системе более высокого уровня сказать «теперь, пожалуйста, соедините source :: foo с dest :: bar» или «удалите связь между source :: red и dest :: blue. ".

В предыдущем примере во время компиляции тип возвращаемого значения из foo() известен программисту как float и может быть указан в исходном коде, поэтому Source<float> можно создать и связать с этой функцией. И тип параметра для bar() также известен как двойной, поэтому Dest<double> может быть создан и связан с этой функцией (с оболочкой std::function). Затем во время выполнения Source<float> можно связать с Dest<double> и передать значение Dest<double> через полиморфный указатель (через унаследованный интерфейс, общий для всех Dest<U> экземпляров). Dest<double> затем вызовет функцию bar(), используя std::function оболочку.

Итак, во время выполнения цель состоит в том, чтобы связать любой Source с любым Dest на произвольную продолжительность и повторно связать в любое время. Поэтому мне нужен способ создать функцию, которая может преобразовывать тип T, известный только во время выполнения, в другой тип U, который также известен только во время выполнения.

Чтобы немного усложнить ситуацию, возвращаемые значения и значения параметров могут быть массивами произвольного размера. Например, foo() может возвращать массив float[32], но bar() может ожидать массив double[8] (возможно, отбрасывая 3 из каждых 4 значений). Я считаю, что этот механизм «Мост» справится с этим, как только он сможет справиться с преобразованием типа.

Честно говоря, я не очень понимаю, как это реализовать. Если бы ассоциации Source-to-Dest были исправлены во время компиляции, я мог бы написать семейство шаблонных Bridge<T,U> функций, которые выполняли бы преобразование, но поскольку все это должно происходить во время выполнения, я не думаю, что это ответ.

Это лучший подход - написать общую Bridge<T,U> функцию, а затем создать какой-то механизм динамической диспетчеризации для выбора подходящего во время выполнения на основе T и U? Как мне определить типы T и U во время выполнения, чтобы выбрать правильный экземпляр Bridge? Я также хотел бы уловить случай, когда T и U являются одним и тем же типом, и, следовательно, избежать ненужного преобразования (в качестве оптимизации).

Или есть лучший способ добиться того, что я хочу делать?


person davidA    schedule 25.03.2013    source источник
comment
разве ты не можешь сделать dynamic_cast ‹type› (переменная)   -  person TravellingGeek    schedule 25.03.2013
comment
Код, демонстрирующий SSCCE, будет иметь долгий путь к получению обратной связи. по этому вопросу.   -  person WhozCraig    schedule 25.03.2013
comment
@WhozCraig: Я работаю над некоторыми примерами, поэтому посмотрю, что я могу сделать, чтобы что-нибудь опубликовать.   -  person davidA    schedule 25.03.2013
comment
@GeraldSv: Мне показалось, что dynamic_cast работает только с указателями и ссылками?   -  person davidA    schedule 25.03.2013
comment
Примитивные типы относительно просты. Самая сложная часть - это непримитивные типы, т. Е. Тип Egg, который преобразуется в Chicken. Некоторые вопросы: можно ли перечислить все типы ввода и вывода? Можете ли вы выполнить сериализацию в оба конца? Можете ли вы написать шаблонный код для каждого типа, который вы добавляете в систему? (то есть, прежде чем вы сможете добавить тип T как Dest<T>, вы должны где-нибудь зарегистрировать тип T). Может ли эта регистрация быть детерминированной во время компиляции? Или вы добавляете сторонние библиотеки DLL с их собственными пользовательскими функциями, которые производят Dest<Egg> и Source<Chicken>?   -  person Yakk - Adam Nevraumont    schedule 25.03.2013
comment
На самом деле меня больше всего беспокоит преобразование между массивами чисел с плавающей запятой и двойными, а целые числа - второстепенная задача. Это часть числовой системы, передающей числовые скаляры и массивы. Основная проблема, с которой я столкнулся с попыткой моего примера до сих пор, заключается в определении базового класса для связи между Source и Dest, поскольку типы с обеих сторон необходимы для правильного определения функции 'send'. Интересно, стоит ли упаковывать значения в массив анонимных символов типа и переинтерпретировать его при получении.   -  person davidA    schedule 25.03.2013
comment
Одна идея, которую я хотел бы попробовать, но у меня возникли проблемы с тем, как это сделать, - это создать и выбрать во время выполнения из набора функций: float-array-to-double-array, double-array-to-to -int-array и т.д., но я не уверен, как можно запросить тип Source или Dest (т.е. T и U) во время выполнения - что-то вроде typeid () в typedef, где typedef определяется внутри шаблона ?   -  person davidA    schedule 25.03.2013
comment
Я могу прибегнуть к простому представлению всего в виде double, а затем std :: function должна обработать преобразование до float, int и т. Д. При вызове последней функции. Не помогает с 64-битными целыми числами, но я все равно не планирую их использовать.   -  person davidA    schedule 25.03.2013