在C ++中检测是否定义了类型:预先声明要探测的内容

上一次 ,我们使用SFINAE来检测类型是否具有定义,并将其与if constexpr和泛型lambda结合使用,以便代码可以使用该类型(如果已定义),同时仍被编译器接受(并被丢弃) )(如果未定义类型)。

但是,我们的用法存在一些问题,有些烦人,有些令人沮丧。

  • 您必须一直说struct
  • 如果类型不存在,则将其命名的行为会将类型注入到当前名称空间中,而不是您希望类型所位于的名称空间中。
  • 您必须使用具有非限定名称的struct技术。 您不能使用它来探测未导入当前名称空间的类型。

我们可以用一个解决方案解决所有三个问题:在所需的名称空间中预先声明类型。



 // awesome.h namespace awesome { // might or might not contain struct special { ... }; } // your code namespace awesome { // ensure declarations for types we // conditionalize on. struct special; } 

一旦完成此操作,就不必说struct因为struct肯定已经声明了。 在call_if_defined中将其用作模板类型参数将不会创建新的声明,因为已经声明了它。 并且由于已经声明了它,因此您可以通过其非限定名称,其完整名称空间名称或介于两者之间的任何名称来访问它。 也是类型别名或从属类型。 (抱歉,它们不在中间。)

 namespace app { void foo() { call_if_defined<awesome::special>([&](auto* p) { // this code is compiled only if "awesome::special" // is defined. Create a local name for "special" // by inferring it from the dummy parameter. using special = std::decay_t<decltype(*p)>; // You can now use the local name "special" to access // the features of "awesome::special". special::do_something(); }); } } 

对于那些从一开始就遵循该系列的人,您可能已经注意到call_if_defined方法与我们之前编写的版本不太相同。 新版本支持多个类型参数,并且仅在定义所有类型时才调用lambda。

让我们仔细看看:

 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语句需要外部括号,而fold表达式需要内部括号。 fold表达式扩展为

  if constexpr ( (is_complete_type_v<T1> && is_complete_type_v<T2> && ... is_complete_type_v<Tn>)) 

lambda的调用使用参数包扩展

  lambda(static_cast<T*>(nullptr)...); 

这扩展到

  lambda(static_cast<T1*>(nullptr), static_cast<T2*>(nullptr), ..., static_cast<Tn*>(nullptr)); 

其中,每种类型的static_cast<T*>(nullptr)重复一次。

如前所述,如果定义了所有类型,则可以使用此函数来调用lambda:

 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游戏重新派生模板的麻烦。

下次 ,我们将其用作跳板并扩展图案。



请注意那些通过搜索引擎到达此处的人 :这是本系列核心部分的最后一部分,但仍有部分内容要讲。 对于不耐烦的人,以下是可复制粘贴的内容:

 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创新的最前沿。 作为负责HoloLens的团队Cognition的一部分,我们现在将专业知识与Azure云的功能相结合,以开发许多新的令人兴奋的服务来推动混合现实体验,例如最近宣布的Azure远程渲染服务。 我们对增强现实,虚拟现实和云技术的融合充满激情,希望能够创造出开创性的混合现实体验。

在Havok工作:

  • 您将与专注于开发的小型团队一起工作
  • 您将有机会在各种尖端的硬件平台和设备上使用新技术。
  • 您将致力于广泛解决具有挑战性的技术问题
  • 您将与世界各地的优秀团队合作

职责范围


  • 设计,开发,测试和交付高质量,高效和干净的多平台C ++代码
  • 开发高度可扩展的Azure服务
  • 直接与内部和外部客户合作以推动产品开发

资历


  • C ++编码和调试技巧
  • 在共享代码库中的团队环境中工作的能力
  • 具有云和分布式服务技术(例如Azure批处理,Azure Blob存储,Docker,遥测)的经验

奖励积分


还有许多其他技能不是必需的,但它们在整个团队中都很有价值,其中包括:

  • C#,ASP.Net,JavaScript,TypeScript,React
  • Unity,虚幻或相关的游戏引擎
  • 具有交互式3D,AR或VR的经验
  • 网络和后端服务
  • 性能优化

您可以在此处获取更多信息并提交简历。

Source: https://habr.com/ru/post/zh-CN459834/


All Articles