type converter
От: SomeOne_TT  
Дата: 26.09.18 09:52
Оценка:
Есть три внешние иерархии типов, которые надо маппить друг в друга.

Первая иерархия построена на enum-like int

namespace ns_val
{
    int APPLE = 0
    int PINEAPPLE = 1
    int PEAR = 2
}

Вторая — классические типы
namespace ns_types
{
    struct Apple
    struct Pineapple
    struct Pear
}


Третья — весьма странный (не понимаю, зачем?) способ

namespace ns_crap
{
struct Fruit:Base_Fruit
{
 public:
    static const Fruit& Apple;
    static const Fruit& Pineapple;
    static const Fruit& Pear;
}
}


Задача — написать конвертер, который маппит значение из одной иерархии в другую.
Желаемый интерфейс — что-то вроде

template <...>
struct Mapping
{
    using type = T;
    int   val;
    Fruit obj;
    
}

from_val<ns_val::APPLE>()::type|obj
from_type<ns_types::Pear>()::obj|val
from_crap<ns_crap::Fruit::Pineapple>()::type|val



Что ни придумаю — выходят какие-то уродцы, да еще и ns_crap::Fruit как темплейт аргумент применить невозможно, т.к. это не тип и не значение.
Какие есть варианты?
Отредактировано 26.09.2018 9:55 SomeOne_TT . Предыдущая версия .
Re: type converter
От: Chorkov Россия  
Дата: 26.09.18 12:11
Оценка: 4 (1)
Здравствуйте, SomeOne_TT, Вы писали:


SO_>Третья — весьма странный (не понимаю, зачем?) способ


SO_>
SO_>namespace ns_crap
SO_>{
SO_>struct Fruit:Base_Fruit
SO_>{
SO_> public:
SO_>    static const Fruit& Apple;
SO_>    static const Fruit& Pineapple;
SO_>    static const Fruit& Pear;
SO_>}
SO_>}
SO_>


Обычно, этот способ применяют когда нужно сказать, что есть стандартные реализации некого интерфейса.
Например :
strcut OnError
{
    virtual void operator() ( const char* ditails="" ) const =0; 
    // ...

    static const OnError& IgnoreAll;
    static const OnError& ThrowException;
    static const OnError& Default; // может совпадать с одной из определенных выше переменных. И вообще определяться в run-time.
};


При этом, в run-time могут гулять не только эти две реализации...

Конвертер точно должен быть compile-time, а не run-time?
Просто использование указателей на ns_crap::Fruit compile-time очень ограниченно.

Если нужно получать ссылку на ns_crap::Fruit, то все просто:

template< int VAL >
struct Mapping_int2obj { static const ns_crap::Fruit& obj; };

template<> const ns_crap::Fruit& Mapping_int2obj< ns_val::APPLE     >::obj =::ns_crap::Fruit::Apple     ;
template<> const ns_crap::Fruit& Mapping_int2obj< ns_val::PINEAPPLE >::obj =::ns_crap::Fruit::Pineapple ;
template<> const ns_crap::Fruit& Mapping_int2obj< ns_val::PEAR      >::obj =::ns_crap::Fruit::Pear      ;

Обратно — никак. (Т.е. только в run-time.)
Может все в run-time перевести, упаковав типы из ns_types в boost::variant<...> ?
Re: type converter
От: Alexander G Украина  
Дата: 26.09.18 12:32
Оценка: 6 (1) +2
Здравствуйте, SomeOne_TT, Вы писали:

SO_>да еще и ns_crap::Fruit как темплейт аргумент применить невозможно, т.к. это не тип и не значение.


Можно. Это переменная с внешним связыванием, можно параметризовать шаблон указателем на неё

template<ns_crap::Fruit*>
...
Русский военный корабль идёт ко дну!
Re[2]: type converter
От: rg45 СССР  
Дата: 26.09.18 12:34
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Можно. Это переменная с внешним связыванием, можно параметризовать шаблон указателем на неё


AG>template<ns_crap::Fruit*>

AG>...

Теперь уже можно и ссылкой, не только указателем.
--
Re[2]: type converter
От: SomeOne_TT  
Дата: 26.09.18 12:51
Оценка:
Здравствуйте, Chorkov, Вы писали:

[code]
C>strcut OnError
C>{
C> static const OnError& Default; // может совпадать с одной из определенных выше переменных. И вообще определяться в run-time.
C>};
[/ccode]

C>При этом, в run-time могут гулять не только эти две реализации...


Понятно, спасибо.

C>Конвертер точно должен быть compile-time, а не run-time?

C>Просто использование указателей на ns_crap::Fruit compile-time очень ограниченно.

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

C>Обратно — никак. (Т.е. только в run-time.)

C>Может все в run-time перевести, упаковав типы из ns_types в boost::variant<...> ?

В учебных целях хотелось бы максимально компил-таймово и без повторений кода.
Re: type converter
От: Voivoid Россия  
Дата: 26.09.18 13:24
Оценка: 6 (1)
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Есть три внешние иерархии типов, которые надо маппить друг в друга.


https://coliru.stacked-crooked.com/a/3db9304bd1696a14

с помощью boost preprocessor можно сделать автоматическую генерацию from_val, from_type и from_crap mapper'ов ( см BOOST_PP_SEQ_FOR_EACH )
Re: type converter
От: rg45 СССР  
Дата: 26.09.18 22:42
Оценка: 9 (1)
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Есть три внешние иерархии типов, которые надо маппить друг в друга.

SO_>Первая иерархия построена на enum-like int
SO_>Третья — весьма странный (не понимаю, зачем?) способ
SO_>Задача — написать конвертер, который маппит значение из одной иерархии в другую.
SO_>Желаемый интерфейс — что-то вроде
SO_>Что ни придумаю — выходят какие-то уродцы, да еще и ns_crap::Fruit как темплейт аргумент применить невозможно, т.к. это не тип и не значение.
SO_>Какие есть варианты?

Я вот здесь набросал. Интерфейс сохранил в точности, как ты показал:

https://ideone.com/Fiv1OQ

Единственное изменение — статические ссылки на объеты Fruit пришлось заменить "живыми" объектами, иначе не удается сделать их параметрами шаблона.

Поддержка:

template <int V, typename T, const ns_crap::Fruit& O>
struct MapEntry
{
   static constexpr int value = V;
   using type = T;
   static constexpr const ns_crap::Fruit& object = O;
};
 
template <int> struct from_val;
template <typename> struct from_type;
template <const ns_crap::Fruit&> struct from_crap;
 
#define MAKE_MAP_ENTRY(value, type, object) \
   template <> struct from_val<value> : MapEntry<value, type, object> {}; \
   template <> struct from_type<type> : MapEntry<value, type, object> {}; \
   template <> struct from_crap<object> : MapEntry<value, type, object> {};


Использование:

MAKE_MAP_ENTRY(ns_val::APPLE, ns_types::Apple, ns_crap::Fruit::Apple)
MAKE_MAP_ENTRY(ns_val::PINEAPPLE, ns_types::Pineapple, ns_crap::Fruit::Pinapple)
MAKE_MAP_ENTRY(ns_val::PEAR, ns_types::Pear, ns_crap::Fruit::Pear)
 
// getting values
static_assert(from_val<ns_val::APPLE>::value == ns_val::APPLE, "");
static_assert(from_type<ns_types::Pineapple>::value == ns_val::PINEAPPLE, "");
static_assert(from_crap<ns_crap::Fruit::Pear>::value == ns_val::PEAR, "");
 
// getting types
static_assert(std::is_same<from_val<ns_val::APPLE>::type, ns_types::Apple>::value, "");
static_assert(std::is_same<from_type<ns_types::Pineapple>::type, ns_types::Pineapple>::value, "");
static_assert(std::is_same<from_crap<ns_crap::Fruit::Pear>::type, ns_types::Pear>::value, "");
 
// getting objects
static_assert(&from_val<ns_val::APPLE>::object == &ns_crap::Fruit::Apple, "");
static_assert(&from_type<ns_types::Pineapple>::object == &ns_crap::Fruit::Pinapple, "");
static_assert(&from_crap<ns_crap::Fruit::Pear>::object == &ns_crap::Fruit::Pear, "");
--
Отредактировано 26.09.2018 22:50 rg45 . Предыдущая версия .
Re[2]: type converter
От: SomeOne_TT  
Дата: 27.09.18 02:41
Оценка:
Здравствуйте, rg45, Вы писали:

R>#define MAKE_MAP_ENTRY(value, type, object) \

R> template <> struct from_val<value> : MapEntry<value, type, object> {}; \
R> template <> struct from_type<type> : MapEntry<value, type, object> {}; \
R> template <> struct from_crap<object> : MapEntry<value, type, object> {};


Изящно, да. Но эти макросы Всегда старался быть от них как можно дальше.
Впрочем, за неимением гербовой возьму твой способ. Спасибо!
Re[3]: type converter
От: rg45 СССР  
Дата: 27.09.18 08:27
Оценка: +1
Здравствуйте, SomeOne_TT, Вы писали:

SO_>Изящно, да. Но эти макросы Всегда старался быть от них как можно дальше.

SO_>Впрочем, за неимением гербовой возьму твой способ. Спасибо!

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