Я не большой специалист в трюкачествах на плюсах но нарисовался у меня следующий код:
Есть темплейтный класс:
template<typename T> class BaseT { private: T m_data; //... public: std::string ToString() const { //.... } };
Есть некая структура с кучей специализированных инстансов:
class Foo { private: BaseT<Bar1> m_bar1; BaseT<Bar2> m_bar2; BaseT<Bar3> m_bar3; BaseT<Bar4> m_bar4; BaseT<Bar5> m_bar5; public: std::string ToString() const { return m_bar1.ToString( ) + m_bar2.ToString( ) + m_bar3.ToString( ) + m_bar4.ToString( ) + m_bar5.ToString( ); } };
Но мне хочется в реализации Foo::ToString писать руками каждое поле. Хочется чтобы оно само, в духе:
std::string Foo::ToString() { std::string res; for( const bar& : m_bar_collection) { res += bar.ToString( ); } return res; }
Однако в коллекцию типа std::vector я их сложить не могу, т.к. типы разные. Как быть? На всякий случай: у Bar1, Bar2, Bar3 и т.п. - есть свои деструкторы, они не виртуальные, Bar1, Bar2, Bar3 - не имеют никакого общего предка.
Унаследуй BaseT от общего базового класса с виртуальным ToString. И сложи в коллекцию указатели на твои разнотипные m_bar.
Можно оставить их как есть, да еще и сложить в коллекцию, а можно от мемберов отказаться, держать их только в коллекции и удалять по счетчикам ссылок. Зависит от того, что еще надо с ними делать, помимо преобразования ToString.
Zab
> Унаследуй BaseT от общего базового класса с виртуальным ToString.
А как это поможет?
MrShoor
> Однако в коллекцию типа std::vector я их сложить не могу, т.к. типы разные. Как быть?
Раз не желаешь иметь общего предка, то никак.
Ну разве что так https://www.geeksforgeeks.org/how-to-iterate-over-the-elements-of… tdtuple-in-c/
Но ИМХО такой хернёй нет смысла заниматься, лучше унаследовать от общего базового класса.
Можно еще сделать на темплейтах как на лиспе. Читай Александреску как оно делается. Но я бы не стал такое городить.
Zab
> И сложи в коллекцию указатели на твои разнотипные m_bar.
Не хочу отдельно указатели отдельно мемберов.
> держать их только в коллекции и удалять по счетчикам ссылок
Вот это было бы замечательно, держать их только в коллекции, только надо без счетчиков, и по возможности без виртуальности. Но даже если виртуального предка от BaseT сделаю, ведь это надо будет еще дополнительно в unique_ptr обернуть каждый объект.
FROL
> Ну разве что так
> https://www.geeksforgeeks.org/how-to-iterate-over-the-elements-of…
> tdtuple-in-c/
О, а std::tuple прикольно, похоже как раз то что надо! Спасибо.
MrShoor
Можно сделать коллекцию без счетчиков и без виртуальности. Прочитай книгу Александреску. Я не хочу тут расписывать всю эту кухню, оно не на одну сотню страниц. А может ты уже и встречался с подобным ранее, тогда будет легче. Если программировал на лиспе, сразу опознаешь механики, темплейты можно признать лиспоподобным универсальным языком, исполняемым на этапе компиляции. Синтаксически ужасно, но приспособиться можно.
Zab
А вообще нет, вот так как ни странно, работает с виртуальной функцией
Zab
> Прочитай книгу Александреску.
Ага, спасибо, можно было еще сказать "загугли".
> Я не хочу тут расписывать всю эту кухню
Обычно так отвечают те, кто собственно не может показать пример как это можно сделать. Потому что пример элементарный же.
Der FlugSimulator
> А вообще нет, вот так как ни странно, работает с виртуальной функцией
Так будет работать, но не хочется заводить отдельно вектор указателей.
MrShoor
Я не люблю такой подход, как у Александреску, он чаще создает проблемы, чем решает их. С какой стати мне его пропагандировать? Ты спросил "можно ли", я ответил "можно" и указал где искать. Захочешь развлечься - найдешь. Как пища для развлечения отлично, но не для практического применения.
А на счет виртуальности ты зря беспокоишься. Да, оно породит дополнительный "лишний" исполняемый постоянно код, может быть неприятно, а в некоторых условиях и неприемлемо. Но ты уже породил ужасные потери, вызвав std::string+std::string+std::string. На их фоне дополнительная виртуальность вообще не видна будет.
Zab
> Но ты уже породил ужасные потери, вызвав std::string+std::string+std::string.
std::string там для примера, у меня там функция сложнее объявлена, и возвращает она не std::string.
FROL
не, std::tuple не подходит, увы. std::get не может же по индексу из переменной читать
MrShoor
> std::get не может же по индексу из переменной читать
может
#include <iostream> #include <string> #include <tuple> int main() { auto t = std::make_tuple( "Zab", "MrShoor", "Funtik"); // index-based access std::cout << "(" << std::get<1>( t) << ")\n"; }
Funtik
> может
Не может:
#include <iostream> #include <string> #include <tuple> int main() { auto t = std::make_tuple( "Zab", "MrShoor", "Funtik"); for ( int i = 0; i < 3; i++) std::cout << "(" << std::get<i>( t) << ")\n"; }
MrShoor
держи https://godbolt.org/z/6jsMEdaez
если же хочешь через tuple, то смотри в сторону std::apply