В прошлый раз, мы использовали SFINAE, чтобы понять, есть ли у типа определение, и мы использовали это в сочетании с
Однако в этом применении существует несколько проблем:
Мы можем исправить все три проблемы с помощью одного решения: предварительно объявить тип в нужном пространстве имен.
После того, как вы это сделали, вам не нужно писать
Те, кто следил за данной серией статей с самого начала, могли заметить, что метод
Посмотрим ближе:
Двойные скобки в if constexpr ((...)) выглядят странно, но они обязательны. Внешние скобки требуются оператором
Вызов лямбды использует расширение пакета параметров:
Это расширяется до
где
Как я уже отмечал ранее, мы можем использовать эту функцию для вызова лямбды, если определены все типы:
C++20 позволяет записать это так:
что позволяет вам называть тип шаблона, тем самым избавляя вас от необходимости заново извлекать его, играя с
В следующей статье мы будем использовать это как трамплин и расширять схему.
Примечание: это четвертая часть основной серии статей, но еще есть и другие части (1,2,3,5). Для нетерпеливых: вот, что нужно скопировать и вставить:
Более десяти лет Havok находится на острие инноваций в разработке игр и интерактивного 3D. Как часть Cognition, команды, отвечающей за HoloLens, мы теперь комбинируем эту экспертизу и силу облака Azure для разработки многих новых захватывающих сервисов, поддерживающих смешанную реальность. Среди них недавно анонсированная служба удаленного рендеринга Azure (Azure Remote Rendering). Мы увлечены совмещением AR, VR и облачных технологий, которые вместе позволяют создавать инновационные практики использования смешанной реальности.
Работа в Havok:
Вы можете узнать больше и подать свою заявку здесь или через LinkedIn.
if constexpr
и универсальными лямбда-выражениями, чтобы код мог использовать тип, если он определен, при этом все еще принимаясь компилятором (и отбрасываясь) если тип не определен.Однако в этом применении существует несколько проблем:
- Каждый раз нужно писать
struct
. - Если тип не существует, то при присвоении ему имени этот тип вводится в текущее пространство имен, а не в пространство имен, в котором вы хотели, чтобы тип был.
- Нужно использовать
struct
с неквалифицированным именем. Нельзя использовать его для проверки типа, который вы не импортировали в текущее пространство имен.
Мы можем исправить все три проблемы с помощью одного решения: предварительно объявить тип в нужном пространстве имен.
// awesome.h
namespace awesome
{
// может или может не содержать
struct special { ... };
}
// ваш код
namespace awesome
{
// обеспечить объявление типов, которые мы детерминируем
struct special;
}
После того, как вы это сделали, вам не нужно писать
struct
, потому что структура была объявлена. Использование ее в качестве параметра типа шаблона в call_if_defined
не приведет к созданию нового объявления, поскольку все уже было объявлено. И так как она была объявлена, вы можете получить к ней доступ через ее неквалифицированное имя, ее полное имя пространства имен или через что-либо между ними. Также через псевдоним типа или зависимый тип (к сожалению, они не между).namespace app
{
void foo()
{
call_if_defined<awesome::special>([&](auto* p)
{
// Этот код компилируется только если "awesome::special"
// определен. Создайте локальное имя для "special"
// выведя его из фиктивного параметра.
using special = std::decay_t<decltype(*p)>;
// Теперь можно использовать локальное имя "special" для доступа
// к параметрам "awesome::special".
special::do_something();
});
}
}
Те, кто следил за данной серией статей с самого начала, могли заметить, что метод
call_if_defined
не совсем совпадает с версией, которую мы написали ранее. Новая версия поддерживает несколько параметров типа и вызывает лямбду, только если определены все типы.Посмотрим ближе:
template<typename... T, typename TLambda>
void call_if_defined(TLambda&& lambda)
{
if constexpr ((... && is_complete_type_v<T>)) {
lambda(static_cast<T*>(nullptr)...);
}
}
Двойные скобки в if constexpr ((...)) выглядят странно, но они обязательны. Внешние скобки требуются оператором
if constexpr
, а внутренние скобки требуются выражением свертки. Выражение свертки расширяется до if constexpr (
(is_complete_type_v<T1> &&
is_complete_type_v<T2> &&
...
is_complete_type_v<Tn>))
Вызов лямбды использует расширение пакета параметров:
lambda(static_cast<T*>(nullptr)...);
Это расширяется до
lambda(static_cast<T1*>(nullptr),
static_cast<T2*>(nullptr),
...,
static_cast<Tn*>(nullptr));
где
static_cast<T*>(nullptr)
повторяется один раз для каждого типа.Как я уже отмечал ранее, мы можем использовать эту функцию для вызова лямбды, если определены все типы:
void foo(Source const& source)
{
call_if_defined<special, magic>(
[&](auto* p1, auto* p2)
{
using special = std::decay_t<decltype(*p1)>;
using magic = std::decay_t<decltype(*p2)>;
auto s = source.try_get<special>();
if (s) magic::add_magic(s);
});
}
C++20 позволяет записать это так:
void foo(Source const& source)
{
call_if_defined<special, magic>(
[&]<typename special, typename magic>
(special*, magic*)
{
auto s = source.try_get<special>();
if (s) magic::add_magic(s);
});
}
что позволяет вам называть тип шаблона, тем самым избавляя вас от необходимости заново извлекать его, играя с
std::decay_t
.В следующей статье мы будем использовать это как трамплин и расширять схему.
Примечание: это четвертая часть основной серии статей, но еще есть и другие части (1,2,3,5). Для нетерпеливых: вот, что нужно скопировать и вставить:
template<typename, typename = void>
constexpr bool is_type_complete_v = false;
template<typename T>
constexpr bool is_type_complete_v
<T, std::void_t<decltype(sizeof(T))>> = true;
template<typename... T, typename TLambda>
void call_if_defined(TLambda&& lambda)
{
if constexpr ((... && is_complete_type_v<T>)) {
lambda(static_cast<T*>(nullptr)...);
}
}
Кстати, у нас есть классная вакансия
Более десяти лет Havok находится на острие инноваций в разработке игр и интерактивного 3D. Как часть Cognition, команды, отвечающей за HoloLens, мы теперь комбинируем эту экспертизу и силу облака Azure для разработки многих новых захватывающих сервисов, поддерживающих смешанную реальность. Среди них недавно анонсированная служба удаленного рендеринга Azure (Azure Remote Rendering). Мы увлечены совмещением AR, VR и облачных технологий, которые вместе позволяют создавать инновационные практики использования смешанной реальности.
Работа в Havok:
- Вы будете работать в небольших командах с талантливыми разработчиками
- У вас будет возможность работать с новыми технологиями на самых разных аппаратных платформах и устройствах
- Вы будете работать над решением сложных технических задач, имеющих огромные перспективы
- Вы будете сотрудничать с крутыми командами по всему миру
Обязанности
- Проектировать, разрабатывать и тестировать высококачественный, эффективный и чистый мультиплатформенный С++ код
- Разрабатывать хорошо-масштабируемые сервисы Azure
- Работать напрямую с внутренними и внешними заказчиками, чтобы стимулировать разработку продукта
Квалификации
- Навыки программирования и отладки на C++
- Умение работать в команде с общим кодом
- Опыт работы с облачными и распределенными сервисными технологиями (например, Azure Batch, Azure Blob Storage, Docker, Telemetry)
Будет плюсом
- C#, ASP.Net, JavaScript, TypeScript, React
- Unity, Unreal или связанные игровые движки
- Опыт в интерактивном 3D, AR или VR
- Сетевые и серверные сервисы
- Оптимизация производительности
Вы можете узнать больше и подать свою заявку здесь или через LinkedIn.
Комментарии (3)
MooNDeaR
19.07.2019 12:40Также через псевдоним типа или зависимый тип (к сожалению, они не между).
Я перечитал эту фразу раза четыре, но так и не понял, что бы она могла значить)
KanuTaH
19.07.2019 19:45+1Ну имеется в виду, что если объявлен некий символ, обозначающий тип, то ты можешь получить к нему доступ по неквалифицированному имени (type_name), по полному имени с учетом всех namespace по пути (A::B::C::type_name), или в ряде случаев через что-то промежуточное (B::C::type_name). Еще можно объявить например type alias для этого типа через using или typedef, но это не будет «чем-то промежуточным». Шутка юмора типа.
P.S. Лучше читать в оригинале, будет более понятно.
kovserg
Для тех кто не следил за серией статей. Какую задачу решает автор? Запутать следы в исходном коде?