Дело такое,
Если простая реализация класса 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;
}
Здравствуйте, 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>, если нужно, предоставляешь специализации. В операторе дергаешь виртуальную функцию.
Здравствуйте, rg45, Вы писали:
R>Добавляешь в placeholder объявление чисто виртуальной функции вывода в поток и реализуешь ее в каждом наследнике impl<T>, если нужно, предоставляешь специализации. В операторе дергаешь виртуальную функцию.
Всё же impl<T> он побольше чем я наисал. В принципе, это первое что я и сделал в первом приближении, но мне не хочется писать 3-4 спецификации impl. Хочется как-то извратиться чтобы иметь возможность надстраивать повеение impl своим типозависимым принтером. который пишется в одну строчку под кокретный тип или работает шаблонная, т.е. дефолтовая версия.
Здравствуйте, Kernan, Вы писали:
R>>Добавляешь в placeholder объявление чисто виртуальной функции вывода в поток и реализуешь ее в каждом наследнике impl<T>, если нужно, предоставляешь специализации. В операторе дергаешь виртуальную функцию. K>Всё же impl<T> он побольше чем я наисал. В принципе, это первое что я и сделал в первом приближении, но мне не хочется писать 3-4 спецификации impl. Хочется как-то извратиться чтобы иметь возможность надстраивать повеение impl своим типозависимым принтером. который пишется в одну строчку под кокретный тип или работает шаблонная, т.е. дефолтовая версия.
Во-первых, большой шаблонный класс обычно легко расклыдвается на стратегии — как раз с той целью, чтоб можно было специализировать маленькие стратегии, а не весь класс. Во-вторых, существует такой вид специализации — специализация нешаблонной функции члена шаблонного класса. Подчиняется тем же правилам, что и специализация обычной шаблонно функции (Т.е. специализация возможно только полная).
И теперь специализируй OutputHelper, сколько душе угодно. Можешь добавить в него шаблонных параметров, если нужно. Можешь оределить в нем operator(), можешь делать все в конструкторе. В общем, что хочешь, то и делаешь.
Здравствуйте, rg45, Вы писали:
R>И теперь специализируй OutputHelper, сколько душе угодно. Можешь добавить в него шаблонных параметров, если нужно. Можешь оределить в нем operator(), можешь делать все в конструкторе. В общем, что хочешь, то и делаешь.
Да уж. До простого решения я не додумался как всегда. Тгогда вот какой вопрос, что делать если принтеров должно быть два и более? Вводить новый шаблонный параметр в impl или в Any? Например, надо выводить данные в лог, в консоль, в базу и в сеть.
Здравствуйте, Kernan, Вы писали:
R>>И теперь специализируй OutputHelper, сколько душе угодно. Можешь добавить в него шаблонных параметров, если нужно. Можешь оределить в нем operator(), можешь делать все в конструкторе. В общем, что хочешь, то и делаешь. K>Да уж. До простого решения я не додумался как всегда. Тгогда вот какой вопрос, что делать если принтеров должно быть два и более? Вводить новый шаблонный параметр в impl или в Any? Например, надо выводить данные в лог, в консоль, в базу и в сеть.
А эти принтеры не связаны между собой общим абстрактным базовым классом? Нельзя в них выводить информацию пользуясь одним лишь базовым интерфейсом? Если можно, то вообще никаких проблем — это обычная реализация вывода, наподобие выводав в std::ostream — один оператор обеспечивает вывод и на консоль, и в файл, и пр. Другое дело, если реализация вывода нужно будет делать для отдельных комбинаций типов данных и принтеров. Тогда это множественная диспетчеризация, паттерн Visitor. И в том и в другом случае это, конечно же, должно быть видно на уровне паблик контакта класса Any.