Простая задачка обощённого программирования
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 17.10.19 14:52
Оценка:
Дело такое,
Если простая реализация класса any которая хранит своё представление через pimpl и type erasure. Мне неоходимо перегрузить оператор вывода << для any чтобы в своём формате выводить impl::T. всего типов 3, один из них std::string.
Как это сделать без РТТИ и красиво чтобы перегуржать только один оператор << под тип?

Концептуально это так выглядит
struct any
{
   ...
   struct placeholder
   {
       virtual ~placeholder() {}
   }

   template<class T>
   struct impl: public placeholder
   {
       T value;
   }
}

operator<<(any& a)
{
   os << a.imp.value;
}
Sic luceat lux!
Отредактировано 17.10.2019 14:54 Kernan . Предыдущая версия .
Re: Простая задачка обощённого программирования
От: rg45 СССР  
Дата: 17.10.19 14:56
Оценка: +3
Здравствуйте, Kernan, Вы писали:

K>Дело такое,

K>Если простая реализация класса any которая хранит своё представление через pimpl и type erasure. Мне неоходимо перегрузить оператор вывода << для any чтобы в своём формате выводить impl::T. всего типов 3, один из них std::string.
K>Как это сделать без РТТИ?

K>Концептуально это так выглядит

K>
K>struct any
K>{
K>   ...
K>   struct placeholder
K>   {
K>       virtual ~placeholder() {}
K>   }

K>   template<class T>
K>   struct impl: public placeholder
K>   {
K>       T value;
K>   }
K>}

K>operator<<(any& a)
K>{
K>   os << a.imp.value;
K>}

K>


Добавляешь в placeholder объявление чисто виртуальной функции вывода в поток и реализуешь ее в каждом наследнике impl<T>, если нужно, предоставляешь специализации. В операторе дергаешь виртуальную функцию.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 17.10.2019 15:00 rg45 . Предыдущая версия . Еще …
Отредактировано 17.10.2019 14:58 rg45 . Предыдущая версия .
Re[2]: Простая задачка обощённого программирования
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 17.10.19 15:04
Оценка:
Здравствуйте, rg45, Вы писали:

R>Добавляешь в placeholder объявление чисто виртуальной функции вывода в поток и реализуешь ее в каждом наследнике impl<T>, если нужно, предоставляешь специализации. В операторе дергаешь виртуальную функцию.

Всё же impl<T> он побольше чем я наисал. В принципе, это первое что я и сделал в первом приближении, но мне не хочется писать 3-4 спецификации impl. Хочется как-то извратиться чтобы иметь возможность надстраивать повеение impl своим типозависимым принтером. который пишется в одну строчку под кокретный тип или работает шаблонная, т.е. дефолтовая версия.
Sic luceat lux!
Re[3]: Простая задачка обощённого программирования
От: rg45 СССР  
Дата: 17.10.19 15:08
Оценка: 13 (2) +3
Здравствуйте, Kernan, Вы писали:

R>>Добавляешь в placeholder объявление чисто виртуальной функции вывода в поток и реализуешь ее в каждом наследнике impl<T>, если нужно, предоставляешь специализации. В операторе дергаешь виртуальную функцию.

K>Всё же impl<T> он побольше чем я наисал. В принципе, это первое что я и сделал в первом приближении, но мне не хочется писать 3-4 спецификации impl. Хочется как-то извратиться чтобы иметь возможность надстраивать повеение impl своим типозависимым принтером. который пишется в одну строчку под кокретный тип или работает шаблонная, т.е. дефолтовая версия.

Во-первых, большой шаблонный класс обычно легко расклыдвается на стратегии — как раз с той целью, чтоб можно было специализировать маленькие стратегии, а не весь класс. Во-вторых, существует такой вид специализации — специализация нешаблонной функции члена шаблонного класса. Подчиняется тем же правилам, что и специализация обычной шаблонно функции (Т.е. специализация возможно только полная).

Эскизно так:

class placehoder
{
public:
    virtual void do_output(std::ostream&) = 0;
};

template <typename> struct OutputHelper;

template <typename T>
class impl : public placeholder
{
    void do_output(std::ostream& output) override
    {
        OutputHelper<T>(output, value);
    }
};


И теперь специализируй OutputHelper, сколько душе угодно. Можешь добавить в него шаблонных параметров, если нужно. Можешь оределить в нем operator(), можешь делать все в конструкторе. В общем, что хочешь, то и делаешь.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 17.10.2019 15:15 rg45 . Предыдущая версия . Еще …
Отредактировано 17.10.2019 15:13 rg45 . Предыдущая версия .
Re[4]: Простая задачка обощённого программирования
От: Kernan Ниоткуда https://rsdn.ru/forum/flame.politics/
Дата: 17.10.19 15:23
Оценка:
Здравствуйте, rg45, Вы писали:

R>И теперь специализируй OutputHelper, сколько душе угодно. Можешь добавить в него шаблонных параметров, если нужно. Можешь оределить в нем operator(), можешь делать все в конструкторе. В общем, что хочешь, то и делаешь.

Да уж. До простого решения я не додумался как всегда. Тгогда вот какой вопрос, что делать если принтеров должно быть два и более? Вводить новый шаблонный параметр в impl или в Any? Например, надо выводить данные в лог, в консоль, в базу и в сеть.
Sic luceat lux!
Re[5]: Простая задачка обощённого программирования
От: rg45 СССР  
Дата: 17.10.19 15:39
Оценка:
Здравствуйте, Kernan, Вы писали:

R>>И теперь специализируй OutputHelper, сколько душе угодно. Можешь добавить в него шаблонных параметров, если нужно. Можешь оределить в нем operator(), можешь делать все в конструкторе. В общем, что хочешь, то и делаешь.

K>Да уж. До простого решения я не додумался как всегда. Тгогда вот какой вопрос, что делать если принтеров должно быть два и более? Вводить новый шаблонный параметр в impl или в Any? Например, надо выводить данные в лог, в консоль, в базу и в сеть.

А эти принтеры не связаны между собой общим абстрактным базовым классом? Нельзя в них выводить информацию пользуясь одним лишь базовым интерфейсом? Если можно, то вообще никаких проблем — это обычная реализация вывода, наподобие выводав в std::ostream — один оператор обеспечивает вывод и на консоль, и в файл, и пр. Другое дело, если реализация вывода нужно будет делать для отдельных комбинаций типов данных и принтеров. Тогда это множественная диспетчеризация, паттерн Visitor. И в том и в другом случае это, конечно же, должно быть видно на уровне паблик контакта класса Any.
--
Не можешь достичь желаемого — пожелай достигнутого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.