C ++, whether the type is defined: preliminary declaration of the necessary objects

Original author: Raymond Chen
  • Transfer
Last time , we used SFINAE to figure out if a type has a definition, and we used it in combination with  if constexpruniversal lambda expressions so that the code could use the type if it was defined, while still being accepted by the compiler (and discarded) if the type is not defined.

However, there are several problems with this application:

  • Every time you need to write  struct.
  • If the type does not exist, then assigning it a name, this type is entered in the current namespace, and not in the namespace in which you wanted the type to be.
  • Must be used  structwith an unqualified name. You cannot use it to check for a type that you did not import into the current namespace.

We can fix all three problems with one solution: first declare the type in the desired namespace.



// awesome.h
namespace awesome
{
  // может или может не содержать
  struct special { ... };
}
// ваш код
namespace awesome
{
  // обеспечить объявление типов, которые мы детерминируем
  struct special;
}

After you have done this, you do not need to write structbecause the structure has been declared. Using it as a template type parameter in  call_if_defined will not lead to the creation of a new declaration, since everything has already been announced. And since she was declared, you can access her through her unqualified name, her full namespace name, or through anything in between. Also through a type alias or a dependent type (unfortunately, they are not between).

namespace app
{
  void foo()
  {
    call_if_defined([&](auto* p)
    {
       // Этот код компилируется только если "awesome::special"
       // определен. Создайте локальное имя для "special"
       // выведя его из фиктивного параметра.
       using special = std::decay_t;
       // Теперь можно использовать локальное имя "special" для доступа
       // к параметрам "awesome::special".
       special::do_something();
    });
  }
}

Those who followed this series of articles from the very beginning might have noticed that the method call_if_defineddoes not quite match the version we wrote earlier. The new version supports several type parameters and calls a lambda only if all types are defined.

Let's take a closer look:

template
void call_if_defined(TLambda&& lambda)
{
  if constexpr ((... && is_complete_type_v)) {
    lambda(static_cast(nullptr)...);
  }
}

The double brackets in if constexpr ((...)) look weird, but they are required. External brackets are required by the operator  if constexpr, and internal brackets are required  by the convolution expression . The convolution expression expands to

  if constexpr (
    (is_complete_type_v &&
     is_complete_type_v &&
     ...
     is_complete_type_v))

The lambda call uses the  parameter package extension :

    lambda(static_cast(nullptr)...);

It expands to

    lambda(static_cast(nullptr),
           static_cast(nullptr),
           ...,
           static_cast(nullptr));

where it   repeats once for each type. As I noted earlier, we can use this function to call the lambda if all types are defined:static_cast(nullptr)



void foo(Source const& source)
{
  call_if_defined(
    [&](auto* p1, auto* p2)
    {
      using special = std::decay_t;
      using magic = std::decay_t;
      auto s = source.try_get();
      if (s) magic::add_magic(s);
    });
}

C ++ 20 allows you to write it like this:

void foo(Source const& source)
{
  call_if_defined(
    [&]
    (special*, magic*)
    {
      auto s = source.try_get();
      if (s) magic::add_magic(s);
    });
}

which allows you to name the type of template, thereby eliminating the need to re-extract it while playing with std::decay_t.

In the next article, we will use this as a springboard and extend the circuit.



Note : this is the fourth part of the main series of articles, but there are still other parts ( 1 , 2 , 3 , 5 ). For the impatient: here's what you need to copy and paste:

template
constexpr bool is_type_complete_v = false;
template
constexpr bool is_type_complete_v
    > = true;
template
void call_if_defined(TLambda&& lambda)
{
  if constexpr ((... && is_complete_type_v)) {
    lambda(static_cast(nullptr)...);
  }
}

By the way, we have a cool job


For more than a decade, Havok has been at the forefront of innovation in game development and interactive 3D. As part of Cognition, the HoloLens team, we are now combining this expertise and the power of the Azure cloud to develop many exciting new mixed-reality services. Among them is the recently announced Azure Remote Rendering service. We are passionate about combining AR, VR and cloud technologies, which together allow us to create innovative practices using mixed reality.

Jobs at Havok:

  • You will work in small teams with talented developers
  • You will have the opportunity to work with new technologies on a variety of hardware platforms and devices.
  • You will work on solving complex technical problems with great prospects
  • You will collaborate with cool teams around the world.

Responsibilities


  • Design, develop and test high-quality, efficient and clean multi-platform C ++ code
  • Develop well-scalable Azure services
  • Work directly with internal and external customers to stimulate product development

Qualifications


  • C ++ programming and debugging skills
  • Ability to work in a team with a common code
  • Experience with cloud and distributed service technologies (e.g. Azure Batch, Azure Blob Storage, Docker, Telemetry)

Will be a plus


  • C #, ASP.Net, JavaScript, TypeScript, React
  • Unity, Unreal or related game engines
  • Experience Interactive 3D, AR or VR
  • Network and server services
  • Performance optimization

You can learn more and submit your application here or through LinkedIn .

Also popular now: