Chief Software Engineer in Game Development
Контакты
Местоположение
Россия, Санкт-Петербург и область, Санкт-Петербург

Достижения

Все достижения (13)

Наибольший вклад в теги

Все теги (66)

Лучшие ответы пользователя

Все ответы (114)
  • Что значит шаблон friend-функции внутри структуры?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    По всем этим вопросам к прочтению предлагаю следующую книгу: Дэвид Вандевурд, Николаи М. Джосаттис: Шаблоны C++....

    Сходу можно сказать что объявление дружественности оператора лишнее - в заблуждение вводит, преимуществ не дает. Внешняя перегрузка конкретно этого оператора в дружественности не нуждается.
    Проверка тут: cpp.sh/73htm

    По поводу конструкций вида "template< typename >" у Вандервуда написано так: "Поскольку шаблонный параметр параметра шаблона далее не используется, его имя можно опустить".
    Это равнозначно объявлению функции вида "void foo( int32_t );". Неиспользуемые идентификаторы можно не писать, но это снижает культуру кода.

    template <class > friend std::ostream& operator<<(std::ostream& s, Vec2<t>& v);

    Параметр опущен потому что не используется. Вместо него используется шаблонный параметр "t" из "Vec2".
    Это нужно для того, чтобы для любого конкретного "t" у "Vec2" был всего один дружественный оператор - инстанцированный от все того же "t".
    Ответ написан
  • Каким образом operator>> попадает в глобальное прогстранство имён?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Тебе стоит ознакомиться с понятием ADL.

    Because of argument-dependent lookup, non-member functions and non-member operators defined in the same namespace as a class are considered part of the public interface of that class (if they are found through ADL)

    Т.е. любая внешняя перегрузка оператора для некоторого типа, определенная в пространстве имен этого типа, является частью интерфейса этого типа и доступна через ADL.

    Также через ADL доступны и дружественные функции, определенные по месту объявления дружественности и не имеющие предшествующего объявления.

    В итоге, operator<< никакими магическими силами не переносится в глобальное пространство имен. Он просто находится по ADL, т.к. правильно реализован и является частью интерфейса соответствующего типа.
    Ответ написан
  • Какое время жизни у переменной?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    auto out = in;
    Тип переменной `out` будет `std::forward_list<T>`. [Пояснение 1], [Пояснение 2]

    Поэтому `out ` будет локальной переменной и будет иметь локальное время жизни.
    Исключением может быть только temporary lifetime extension. Тогда время жизни переменной продлится.
    The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.
    Ответ написан
  • Что не даёт на C++ писать кроссплатформенные приложения?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Да, как бы, ничего не мешает писать один С++ код для множества платформ. Почти весь мой трудовой стаж связан именно с разработкой кроссплатформенных игр. Я работал с несколькими (самодельными и не очень) движками и имею свое собственное детище, прекрасно и однозначно собирающееся на 5 целевых платформ (Win, Mac, Linux, ios, Android), к которым без труда можно добавить и консоли, и новые платформы.

    Нет, вру, не без труда. Попотеть над слоем абстракции придется. Но попотеть придется только над ним, все остальное заведется само, т.к. изначально написано в стандарте C++, без расширений под конкретные компиляторы, и с применением ряда очень важных для кроссплатформенности подходов.

    Кроссплатформенность подразумевает решение ряда вопросов, которые и выливаются в слой абстракции над операционной системой. Эти вопросы, зачастую, решать никто не хочет. Несколько раз встречал такое сам и еще мне рассказывали о том, как тот или иной движок сперва был только под конкретную ###, а потом решили портировать на @@@. Оказалось, что компилятор, которым всегда и собирали движок, нашпигован расширениями языка, которые конечно же все пользовали на 100%, и при смене компилятора ни один файл исходников не остался без доброй сотни ошибок. Т.е. переписывать надо было ВСЁ.

    Mercury13 хорошо рассказал про Unicode пути к файлам. Drakonoved правильно подметил про разделители путей к файлам. Максим Гришин очень хорошо напомнил про порядок следования байт. Это все и есть часть этого ряда вопросов.
    У каждой платформы есть свой API, которого не будет на другой платформе. Но на другой платформе будет свой API, со своими именами и схожей функциональностью. И работу с API надо абстрагировать от универсального кода.
    Еще, на одной платформе у тебя может быть разомкнутый главный цикл обработки сообщений (Win), а на другой - замкнутый (Android). Надо подстраиваться. GUI везде разный, надо подстраиваться. Сама структура приложения на одной платформе может быть монолитной, а на другой - композиционной. Графические и звуковые API могут быть и кроссплатформенными, однако простоты использования это им не прибавляет. Инициализация все равно будет платформозависимой.
    На самом деле даже в рамках работы на одной платформе надо соблюдать ряд правил, чтобы иметь возможность из одного кода получать и 32-битное приложение, и 64-битное тоже. Об этом неплохо написано на сайте разработчиков PVS-Studio.

    И все это решается. От части - с помощью архитектурных приемов. Один из таких я уже показывал в другом своем ответе.
    И еще эти вопросы можно не решать.
    ДубльГИС, например, уже давно работает на базе Qt, что сильно упростило им кроссплатформенную жизнь. Qt решает ряд проблем кроссплатформенности.
    Ответ написан
  • Как раскрыть parameter pack для передачи типов в шаблонную функцию?

    @MarkusD Куратор тега C++
    все время мелю чепуху :)
    Ошибка, которую видно в коде, это ошибка использования parameter pack.
    В коде у тебя видно раскрутку списка параметров, в ходе которой список неизбежно станет пустым и произойдет попытка инстанцировать вызов mapClasses<>(). И именно эта попытка приводит к ошибке.

    И эту ошибку можно убрать. Для этого у нас сейчас есть аж целых три способа.

    Способ первый - C++17 constexpr if.
    template< typename U, typename... args >
    void mapClasses()
    {
    	// ...
    	if constexpr( sizeof...( args ) > 0 ) // Все понятно и без слов.
    	{
    		mapClasses<args...>();
    	}
    }


    Способ второй - частная специализация класа/структуры.
    template< typename... args >
    struct Map;
    
    template< typename U >
    struct Map<U>
    {
    	static inline void mapClasses()
    	{
    		// ...
    	}
    };
    
    template< typename U, typename... args >
    struct Map<U, args...>
    {
    	static inline void mapClasses()
    	{
    		Map<U>::mapClasses();
    		Map<args...>::mapClasses();
    	}
    };


    Способ третий - самый коварррный - использование SFINAE в классическом его смысле.
    template< typename U >
    void mapClasses()
    {
    	// ...
    }
    
    // SFINAE тут (аргумент функции) выключит вывод шаблона при пустом списке полей.
    // В этом случае доступным остается только верхний экземпляр функции.
    template< typename U, typename... args >
    void mapClasses( char (*)[ sizeof...( args ) > 0 ] = 0 )
    {
    	mapClasses<U>();
    	mapClasses<args...>();
    }
    Ответ написан