Сообщение Re[3]: наборы от 25.09.2023 14:34
Изменено 25.09.2023 14:40 Sm0ke
Re[3]: наборы
Здравствуйте, Евгений Музыченко
Это обсуждение привело меня к размышлениям над смежной темой.
А именно об отделдении структур для хранения данных от
набора действий над ними.
Вот к примеру есть некий класс, который что-то хранит.
Если все действия, сваязяанные с его обработкой, запихать как методы в него
то он начинает разрастаться и "мозолить взгляд"
Мне знакомо пожелание разработчика определить общие действия над разными данными
, и как-то их сгруппировать.
В итоге я написал вот такой простенький пример — один из вариантов — как это можно осуществить.
link: https://godbolt.org/z/q3x7TcfE5
Что тут происходит?
В траите io_actions только два метода read() и write(), которые работают с приватными данными из некого класса restrict
Понятно, что в дальнейшем можно определить и дополнительные отдельные траиты (наборы действий), скажем преобразования, проверка, да что угодно
, и оформить их как отдельный nest.
Почему я оформил trait как шаблонный?
Просто в данном случае конкретый обработчик может быть разным (консоль, файл, сеть, ещё куда)
И тут сами конкретные обработчики тоже not_over_bloated тучей кучей методов) а просто что-то хранят
Такая штука работает без интерфейса с виртуальными методами, которые хочется по возможности избежать.
Кстати, в примере выше нет definition для класса t_file
Вроде не сложно его сделать по анологии, если он вообще нужен
А действия тогда будут заданы как-то так:
p/s
Оператор стрелка у t_console создаёт временный объект-wrapper, это вообще-то под вопросом — как лучше можно оформить)
Это обсуждение привело меня к размышлениям над смежной темой.
А именно об отделдении структур для хранения данных от
набора действий над ними.
Вот к примеру есть некий класс, который что-то хранит.
Если все действия, сваязяанные с его обработкой, запихать как методы в него
то он начинает разрастаться и "мозолить взгляд"
Мне знакомо пожелание разработчика определить общие действия над разными данными
, и как-то их сгруппировать.
В итоге я написал вот такой простенький пример — один из вариантов — как это можно осуществить.
link: https://godbolt.org/z/q3x7TcfE5
#include <type_traits>
#include <iostream>
struct t_file;
struct t_console;
struct restrict;
template <typename Type>
struct io_actions
{
using pointer = Type *;
// data
pointer self;
// methods
void read(restrict & p);
void write(restrict & p);
// hint
io_actions * operator -> () { return this; }
};
struct restrict
{
friend void io_actions<t_console>::write(restrict &);
friend void io_actions<t_console>::read(restrict &);
friend void io_actions<t_file>::write(restrict &);
friend void io_actions<t_file>::read(restrict &);
private:
int value{55};
};
struct t_console
{
using trait = io_actions<t_console>;
// data
std::istream * in{& std::cin};
std::ostream * out{& std::cout};
trait operator -> () { return {this}; }
};
template <> void t_console::trait::read(restrict & p) { (*self->in) >> p.value; }
template <> void t_console::trait::write(restrict & p) { (*self->out) << p.value; }
int main()
{
restrict v;
t_console c;
c->write(v);
return 0;
}
Что тут происходит?
В траите io_actions только два метода read() и write(), которые работают с приватными данными из некого класса restrict
Понятно, что в дальнейшем можно определить и дополнительные отдельные траиты (наборы действий), скажем преобразования, проверка, да что угодно
, и оформить их как отдельный nest.
Почему я оформил trait как шаблонный?
Просто в данном случае конкретый обработчик может быть разным (консоль, файл, сеть, ещё куда)
И тут сами конкретные обработчики тоже not_over_bloated тучей кучей методов) а просто что-то хранят
Такая штука работает без интерфейса с виртуальными методами, которые хочется по возможности избежать.
Кстати, в примере выше нет definition для класса t_file
Вроде не сложно его сделать по анологии, если он вообще нужен
А действия тогда будут заданы как-то так:
template <> void t_file::trait::read(restrict & p) { /* ... */ }
template <> void t_file::trait::write(restrict & p) { /* ... */ }
p/s
Оператор стрелка у t_console создаёт временный объект-wrapper, это вообще-то под вопросом — как лучше можно оформить)
Re[3]: наборы
Здравствуйте, Евгений Музыченко
Это обсуждение привело меня к размышлениям над смежной темой.
А именно об отделдении структур для хранения данных от
набора действий над ними.
Вот к примеру есть некий класс, который что-то хранит.
Если все действия, сваязяанные с его обработкой, запихать как методы в него
то он начинает разрастаться и "мозолить взгляд"
Мне знакомо пожелание разработчика определить общие действия над разными данными
, и как-то их сгруппировать.
В итоге я написал вот такой простенький пример — один из вариантов — как это можно осуществить.
link: https://godbolt.org/z/q3x7TcfE5
Что тут происходит?
В траите io_actions только два метода read() и write(), которые работают с приватными данными из некого класса restrict
Понятно, что в дальнейшем можно определить и дополнительные отдельные траиты (наборы действий), скажем преобразования, проверка, да что угодно
, и оформить их как отдельный nest.
Почему я оформил trait как шаблонный?
Просто в данном случае конкретый обработчик может быть разным (консоль, файл, сеть, ещё куда)
И тут сами конкретные обработчики тоже not_over_bloated тучей кучей методов) а просто что-то хранят
Такая штука работает без интерфейса с виртуальными методами, которые хочется по возможности избежать.
Кстати, в примере выше нет definition для класса t_file
Вроде не сложно его сделать по анологии, если он вообще нужен
А действия тогда будут заданы как-то так:
p/s
Оператор стрелка у t_console создаёт временный объект-wrapper, это вообще-то под вопросом — как лучше можно оформить)
upd
По поводу iostream: я просто старался чтобы пример был понятным
Это обсуждение привело меня к размышлениям над смежной темой.
А именно об отделдении структур для хранения данных от
набора действий над ними.
Вот к примеру есть некий класс, который что-то хранит.
Если все действия, сваязяанные с его обработкой, запихать как методы в него
то он начинает разрастаться и "мозолить взгляд"
Мне знакомо пожелание разработчика определить общие действия над разными данными
, и как-то их сгруппировать.
В итоге я написал вот такой простенький пример — один из вариантов — как это можно осуществить.
link: https://godbolt.org/z/q3x7TcfE5
#include <type_traits>
#include <iostream>
struct t_file;
struct t_console;
struct restrict;
template <typename Type>
struct io_actions
{
using pointer = Type *;
// data
pointer self;
// methods
void read(restrict & p);
void write(restrict & p);
// hint
io_actions * operator -> () { return this; }
};
struct restrict
{
friend void io_actions<t_console>::write(restrict &);
friend void io_actions<t_console>::read(restrict &);
friend void io_actions<t_file>::write(restrict &);
friend void io_actions<t_file>::read(restrict &);
private:
int value{55};
};
struct t_console
{
using trait = io_actions<t_console>;
// data
std::istream * in{& std::cin};
std::ostream * out{& std::cout};
trait operator -> () { return {this}; }
};
template <> void t_console::trait::read(restrict & p) { (*self->in) >> p.value; }
template <> void t_console::trait::write(restrict & p) { (*self->out) << p.value; }
int main()
{
restrict v;
t_console c;
c->write(v);
return 0;
}
Что тут происходит?
В траите io_actions только два метода read() и write(), которые работают с приватными данными из некого класса restrict
Понятно, что в дальнейшем можно определить и дополнительные отдельные траиты (наборы действий), скажем преобразования, проверка, да что угодно
, и оформить их как отдельный nest.
Почему я оформил trait как шаблонный?
Просто в данном случае конкретый обработчик может быть разным (консоль, файл, сеть, ещё куда)
И тут сами конкретные обработчики тоже not_over_bloated тучей кучей методов) а просто что-то хранят
Такая штука работает без интерфейса с виртуальными методами, которые хочется по возможности избежать.
Кстати, в примере выше нет definition для класса t_file
Вроде не сложно его сделать по анологии, если он вообще нужен
А действия тогда будут заданы как-то так:
template <> void t_file::trait::read(restrict & p) { /* ... */ }
template <> void t_file::trait::write(restrict & p) { /* ... */ }
p/s
Оператор стрелка у t_console создаёт временный объект-wrapper, это вообще-то под вопросом — как лучше можно оформить)
upd
По поводу iostream: я просто старался чтобы пример был понятным