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.
В целом, это не код, а каша-какаша. Его надо просто переписать.
С дизайном кода в текущих условиях помочь не смогу, т.к. опять же надо дать ответы на те мои вопросы. Нужно сперва понять ожидания от кода и только тогда определять видение и дизайн кода.
MayRiv , какая цель у содержания константной ссылки на объект? Какая цель у const rvalue в конструкторе?
По этим вопросам нужно техническое обоснование. Наперед скажу что этот код семантически неверен вне зависимости от наличия обоснования и его качества. Но обоснование все равно нужно. Нужно понять требования к коду и определить направление его дизайна.
Список инициализации приведенного конструктора неясен. Какое поведение от него ожидается?
Какое поведение ожидается от std::make_shared(std::move(...)) в приведенном коде? Какая цель у этой конструкции?
Да, я мог бы сразу указать на все ошибки в этом коде, но не в них суть. В коде видно ошибки другого уровня, поэтому задаю вопросы.
Станислав Макаров , странно что ты не привел catch-all (3) пример.
Безусловно, в общем случае это решение приводит к проблемам, но только в общем случае. К тому же, это именно то, что нужно автору.
Recardo_Recoly , все равно ничего не понятно. Тебе явно плохо дается доказательство без знаний. :)
Бросай затею обойтись минимумом разглашения информации. Предоставь код, возможно так будет понятнее, что тебе надо.
Если что, обобщенная функция сериализации могла бы выглядеть вот так:
template< typename TValue >
inline void Write( const TValue& value );
template<>
inline void Write( const std::string& value ) {}
template<>
inline void Write( const std::wstring& value ) {}
template<>
inline void Write( const int32_t& value ) {}
Юля , камеры разные бывают. :)
Бывают камеры сгорания, бывают камеры в шинах, бывают камеры хранения или камеры в тюрьме. Тебе для каких камер библиотеку хочется сделать?
Мои слова лишены стеба, я просто хочу сказать что в твоем вопросе нет никакой конкретики.
Тебе стоит описать внешний интерфейс библиотеки, ее функциональность и перечислить решаемые задачи. Это будет конкретикой. Когда появится конкретика, ее можно будет декомпозировать на задачи. Задачи уже можно будет связать по зависимостям между собой. Это уже даст представление (Vision) библиотеки. Декомпозицией задач можно заниматься до получения атомарных задач на введение небольшой неделимой части функциональности библиотеки. И только на уровне атомарной задачи можно будет рассуждать о шаблонах проектирования.
Ben_r007 , тебеб, для начала, определиться бы со своими целями. :)
Твоя цель - это "делать" или "создать"? Делать игру или создать игру?
Если первое, то бери C, C++ тебе не нужен. Чем ниже уровень языка, тем лучше. Дорогу осилит идущий.
Если второй вариант, то тебе нужны Python или, многократно лучше, Lua в составе готового пакета разработки игр.
Самое первое, что стоит понять - это что нет никакого vs между C и C++. Вообще нет.
Вопрос некорректен. :)
Лежебокер , очень советую ознакомиться с документацией на операторы new и delete.
Очень важно понимать, что в общем случае связка "new[] - delete" - это Undefined Behavior.
Безусловно, реализация delete[] обычно сводится к циклу финализации и вызову простого delete. Но это не значит что этим можно пользоваться. Одна маленькая правка и у тебя в коде UB, приехали.
Лучше будет положиться на оптимизацию компилятора, он все сделает как надо.
res2001 , добавлю тебе в ответ мои пять копеек.
В отладочной сборке не "скорее всего", а точно включается код проверки целостности кучи.
Если иметь окружение MS Visual Studio, то при отладке даже сама куча работает в режиме отладки. Это уже означает, что при выделении памяти происходит маркировка ее границ - установка т.н. забора, а в заголовке выделенного участка пишутся дополнительные данные.
Сам забор из себя представляет 4 одинаковых байта перед выделенным участком (и после его заголовка) и 4 таких же одинаковых байта сразу после выделенного участка.
При освобождении выделенной памяти делается гора проверок, среди которых - проверка целостности забора. Это - одна из основных причин падения производительности при запуске в отладке в MS VC++.
Кирилл Журавлев , у тебя код явно забор ломает. Тебе стоит проверить, соблюдаются ли у тебя диапазоны в циклах и правильные ли индексы используются при записи в твой массив.
Я в твой код въезжать не планирую, поэтому ответов не даю. Просто проверь индексы.
К тому же, res2001 все качественно описал.
Плюсы - это инструмент. Джун для работы на плюсах уже должен знать стандарт.
UE/Qt/и.т.д. - это тоже инструменты.
Дело в том, что знание инструментов никак не характеризует уровень профессионализма человека.
Все эти карты освоения - это странные штуки для узкозашоренных "специалистов".
Инженер решает задачи с помощью разных инструментов. Инструментом нужно уметь владеть. Знание документации инструмента никак не означает владение инструментом, это лишь базовая ступень на пути владения. Инструментом владеть мало, надо еще уметь выбирать инструмент. Теория выбора инструмента для решения задач - это тоже лишь малая часть пути к способности выбирать инструмент.
А основным инструментом для любого инженера всегда были расчеты.