Дмитрий Иванов , мнеб не хотелось, откровенно говоря, быть автором такого ответа. :)
Сможешь подправить ссылку с меня на Adamos-а в своем ответе?
Кстати, советую еще решением отметить ответ Виталия, т.к. он более подходит в обобщенном смысле.
Дмитрий Иванов , а давай еще напишем причину такой необходимости. Обычно такие выкрутасы бывают нужны только в двух случаях: 1- когда есть проблемы с организацией класса; 2- когда хочется быть злобным буратиной и сильно испортить себе(или другим) жизнь.
Варианты решения вопроса есть, но чтобы с ними определиться, сперва надо понять его исподнюю.
ведь производительность упадет, по сравнению с обычными указателями
Для поддержки этого утверждения требуется детальное обоснование с приведением расчетов, разработкой методологии тестирования и доказательством через тестирование.
Иначе утверждение является голословным.
Артем , полиморфизм в плюсах делается так же. Но есть одно важное отличие.
В плюсах объекты могут храниться и передаваться по значению. В твоем Strategy[N] по своему значению будут лежать именно объекты типа Strategy, но не другого типа. Если хранить по ссылке или по указателю, то уже можно реализовать паттерн интерфейса.
Этот вопрос уже относится к самым базовым навыкам владения языком. С полиморфизмом, наследованием и виртуальностью тебе стоит разобраться самому.
Не рассмотрите вариант кратковременной платной консультации?
Точно не рассмотрю. :) Я вижу что времени потребуется очень много, а мое время само по себе дорого. Т.е. сумма выйдет неподъемная и того она не стоит.
Это базовый материал, он довольно легко осваивается в личном порядке. :)
Артем , ну да, мышление ты себе после PHP еще долго ломать будешь. :)
Но это если тебе хочется нормально писать на плюсах. А если не хочется, то с тонкостями плюсов лучше и не париться.
Strategy - это, я так понимаю, ты просто назвал сущность по имени паттерна? Не самая лучшая мысль, слово слишком абстрактное и ничего не отражает. Хотя, в целом, не суть.
А для чего тебе две активных стратегии в одно время? Почему не одна разединственная?
Артем , смотри, давай загоним весь этот код в спойлеры, он не так интересен, как описание твоего вопроса.
А следом давай более внятно распишем, для чего тебе эти стратегии нужны, зачем их сохранять в персистентную память и какой толк держать их в массиве.
Сейчас на твой вопрос не получится дать ответ. Понятность вопроса под большим сомнением.
shmelevka , основная загвоздка в том, что нет Jun/Mid/Chif C++ Developer, есть Jun/Mid/Chif Software Engineer.
Плюсы - это инструмент. Джун для работы на плюсах уже должен знать стандарт.
UE/Qt/и.т.д. - это тоже инструменты.
Дело в том, что знание инструментов никак не характеризует уровень профессионализма человека.
Все эти карты освоения - это странные штуки для узкозашоренных "специалистов".
Инженер решает задачи с помощью разных инструментов. Инструментом нужно уметь владеть. Знание документации инструмента никак не означает владение инструментом, это лишь базовая ступень на пути владения. Инструментом владеть мало, надо еще уметь выбирать инструмент. Теория выбора инструмента для решения задач - это тоже лишь малая часть пути к способности выбирать инструмент.
А основным инструментом для любого инженера всегда были расчеты.
Kalombyr , ты ведь понимаешь, какой набор из самых экстраординарных ошибок и самых замысловатых трудностей ты для себя откроешь после добавления подобного механизма?
Армен , буквально? Черную магию! :)
Это называется SFINAE.
Аргумент функции в третьем варианте - это зануленный по умолчанию массив из указателей на функцию, один из путей SFINAE.
В случае если этот массив имеет нулевую длину, вывод шаблона проваливается, но сама компиляция продолжится только если есть перегруженная функция, удовлетворяющая условиям вызова.
SFINAE сработает тогда, когда список параметров будет пустым, это оборвет вывод шаблона и оставит только один вариант для вызова mapClasses<U>().
Армен , компилятор тебе не ту ошибку пишет, что ты описал. :)
Приведи текст самой ошибки, по ней будет понятно.
Упреждая ответы, могу подсказать одну важную штуку. Ты делаешь раскрутку списка типов, тебе нехватает концевого случая, когда в args у тебя пустой список. И это не так-то просто сделать без 17го стандарта.
Recardo_Recoly , тут я могу только посоветовать поизучать метапрограммирование. :)
Есть вариант не писать почти одинаковый код для каждого типа, а обойтись только универсальными конструкциями для семейств типов. Но тебе надо обладать базисом знаний метапрограммирования. Обладать им нужно именно тебе хотябы просто потому что если вот я возьму и выкачу тебе рабочий код, он не будет решать полностью всех нужных тебе задач. И тебе потребуется расширить его, но ты ведь не сможешь. А это уже потеря самостоятельности.
У тебя есть задача: сделать сериализацию значения произвольного типа.
Включаем моск и начинаем думать. Как нам через одно имя функции обработать значения разных типов? Для этого у нас есть два механизма. Всего два.
Первый механизм - это перегрузка функции. Удобная, простая как грабли. Главное - объявления вовремя подпихивай и все будет работать.
Второй механизм - это шаблон функции и его частная специализация для конкретного типа данных. Это уже посложнее.
Зачем тебе std::string из TValue, если TValue - это параметр шаблона? TValue становится известным только в момент вывода шаблона для конкретного типа. У тебя есть возможность сделать частную специализацию для типа std::string, в рамках которой уже нет никакого TValue, а есть конкретный std::string.
При использовании любого из двух механизмов ты приходишь к одинаковому по своей сути выходу - у тебя есть функция, в которой есть параметр конкретного типа, с которым строго понятно как и что делать.
Посмотри у меня в примере повнимательнее. У меня нет определения для шаблонной функции, есть только ее объявление. И это крайне важный момент.
Определения есть только для случаев частной специализации этого шаблона. И это второй важный момент.
MayRiv , мой ответ тут явно не нужен в таком случае, но пояснения я сделаю.
Смотри...
Чисто механически, между ссылкой и указателем разницы мало. Ссылка обязательна к инициализации при объявлении, не может быть переназначена и не требует разыменования. Указатель может быть нулевым, требует разыменования и может быть переназначен. Нужно понимать что и ссылка, и указатель, по своей сути - это граната без чеки в руках. Держи уверенно, но нежно, иначе все будет плохо.
const rvalue - это нонсенс. Нужно убрать.
Поле-ссылка на объект может использоваться только если время жизни объекта со ссылкой гарантированно меньше времени жизни объекта по ссылке. Иначе все плохо.
В идеале, раз уж используете разделяемое владение (std::shared_ptr), то его и надо хранить, передавать, разделять и просто использовать.
std::make_shared нужен для того, чтобы сформировать объект с разделяемым владением в едином неразрывном блоке памяти вместе с контрольным счетчиком владения. В качестве аргументов для std::make_shared передаются аргументы конструктора объекта. Зачем разыменовывать один std::shared_ptr и формировать перемещающую ссылку для конструирования другого std::shared_ptr? Это выглядит как нонсенс.
Если надо переместить объект с разделенным владением, то лучше сделать перемещающее присвоение между инстанциями std::shared_ptr.
В целом, это не код, а каша-какаша. Его надо просто переписать.
С дизайном кода в текущих условиях помочь не смогу, т.к. опять же надо дать ответы на те мои вопросы. Нужно сперва понять ожидания от кода и только тогда определять видение и дизайн кода.
Сможешь подправить ссылку с меня на Adamos-а в своем ответе?
Кстати, советую еще решением отметить ответ Виталия, т.к. он более подходит в обобщенном смысле.