Добрый день, коллеги.
Возникла следующее не совсем здоровое желание. Хотелось бы иметь функцию (фабрику), возвращающую объекты произвольных типов, и, затем, в зависимости от типа возвращенного объекта приложение должно автоматически разруливать, какую из нескольких версий перегруженной функции (различающейся по типу аргумента) вызывать.
Псевдокод:
enum ObjectType
{
INT,
CHAR,
...
};
class Int
{
public:
Int( string & value );
};
class Char
{
Char( string & value );
};
??? TypeFactory( ObjectType type, string value )
{
switch( type )
{
case INT:
return( Int( value ));
case CHAR:
return( Char( value ));
}
}
void foo( Int );
void foo( Char );
// Где-то в коде...
string value( "1" );
ObjectTeyp type = GetTypeOfValue( string value( "1" ));
foo( TypeFactory( type, value )); // <-- Вот здесь должна вызваться правильная версия foo() в зависимости от типа
Такое как-то реализуемо? Что должна возвращать TypeFactory, и как объявить foo(), чтобы компилятор понимал, какую ее версию следует вызывать?
Здравствуйте, Аноним, Вы писали:
А>Добрый день, коллеги. А>Возникла следующее не совсем здоровое желание. Хотелось бы иметь функцию (фабрику), возвращающую объекты произвольных типов, и, затем, в зависимости от типа возвращенного объекта приложение должно автоматически разруливать, какую из нескольких версий перегруженной функции (различающейся по типу аргумента) вызывать.
Здесь классический ООП подойдёт
class IFooable
{
virtual void callFoo() = 0;
};
typedef std::shared_ptr<IFooable> PFooable;
class Int : public IFooable { ..... };
class Char : public IFooable { ..... };
PFooable TypeFactory(.....) { ..... return PFooable(new Int(...)); ..... }
void foo(PFooable obj) { ..... obj->callFoo(); ..... }
К нему можно прикрутить С++ные плюшки, такие, как автоматическую диспетчеризацию к перегруженным foo
template<class Final> class FooableImpl // CRTP
{
virtual void callFoo() /*override*/ { foo(static_cast<Final*>(this)); }
};
void foo(PFooable obj) { obj->callFoo(); }
class Int;
void foo(Int*);
class Int : public FooableImpl<Int> { ..... };
Есть ещё пара альтернативных решений, но они слишком кудрявы, по сравнению с этим.
Здравствуйте, Аноним, Вы писали:
А>Добрый день, коллеги. А>Возникла следующее не совсем здоровое желание. Хотелось бы иметь функцию (фабрику), возвращающую объекты произвольных типов, и, затем, в зависимости от типа возвращенного объекта приложение должно автоматически разруливать, какую из нескольких версий перегруженной функции (различающейся по типу аргумента) вызывать.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, jazzer, Вы писали:
J>>Boost.Variant (и его static_visitor):
К>В принципе, да! Раз уж все типы перечислены в enum ObjectType, то можем себе позволить вариантный тип.
К>Тогда можно и ещё дальше пойти: сделать mpl-отображение этого перечисления на типы, и фабрику нагенерить автоматически.
Да и енум, в принципе, не нужен: список типов + make_variant_over. А если все-таки нужен, то в каком-то таком виде:
typedef boost::mpl::vector< int, char,... > ObjectTypes;
template< class T >
struct ObjectTypeIdx : boost::mpl::distance<
typename boost::mpl::begin< ObjectTypes >::type
, typename boost::mpl::find< ObjectTypes, T >::type
> {};
...
ObjectTypeIdx< int >::value;
ObjectTypeIdx< char >::value;
...
Здравствуйте, Warturtle, Вы писали:
К>>Тогда можно и ещё дальше пойти: сделать mpl-отображение этого перечисления на типы, и фабрику нагенерить автоматически. W>Да и енум, в принципе, не нужен: список типов + make_variant_over. А если все-таки нужен, то в каком-то таком виде:
То есть, получаем такую архитектуру
— примитивный тип (int,char,etc...)
— его числовой идентификатор
— его обёртка (Int,Char,etc...), которую, скорее всего, можно нагенерить из шаблона
— вариантный тип — упаковка обёрток
— фабрика обёрток по номеру
— перегруженная для обёрток функция foo, а скорее всего, её тоже можно нагенерить из шаблона
И всё это развёртывается из списка примитивных типов!
Здравствуйте, jazzer, Вы писали:
J>Ну да, так и делается обычно в наших MPL-ях, чего тут такого J>
Да всё неплохо, кроме рокет-саенса или вуду-мэджика.
Больше того, не составит труда сделать всё то же самое на препроцессоре, — но это будет больше вуду, чем рокет.
Здравствуйте, Аноним, Вы писали:
А>Добрый день, коллеги. А>Возникла следующее не совсем здоровое желание. Хотелось бы иметь функцию (фабрику), возвращающую объекты произвольных типов, и, затем, в зависимости от типа возвращенного объекта приложение должно автоматически разруливать, какую из нескольких версий перегруженной функции (различающейся по типу аргумента) вызывать.
Гуглите кейворд dynamic dispatch, можно найти достаточно много вариантов В дополнение к уже озвученному (с использованием виртуальных функций и вариантного типа), напомню, что есть RTTI, typeid() и класс type_info.