C++ 20的条件显式构造函数

explicit(bool) 是C++ 20的特性,用于简化泛型类型的实现和提高编译时性能。

null

在C++中,通常使用编写其他类型的对象的类型来编写和使用。 std::pair std::optional 有两个例子,但是在标准库Boost中还有很多其他的例子,很可能还有您自己的代码库。跟随 最小惊奇原则 ,确保这些包装器尽可能合理地保留其存储类型的行为是值得的。

采取 std::string 举个例子。它允许从字符串文本进行隐式转换,但是 std::string_view :

void f(std::string);

f(“hello”);   //compiles
f(“hello”sv); //compiler error

这是通过 std::string 通过标记 std::string_view 作为 明确的 .

如果我们正在编写一个包装器类型,那么在许多情况下,我们都希望公开相同的行为,即如果存储的类型允许隐式转换,那么我们的包装器也会这样做;如果存储的类型没有,那么我们的包装器如下 [1] . 更具体地说:

void g(wrapper<std::string>);

g("hello");   //this should compile
g("hello"sv); //this should not

实现这一点的常用方法是使用SFINAE。如果我们有一个像这样的包装 [2] :

template<class T>
struct wrapper {
  template <class U>
  wrapper(U const& u) : t_(u) {}

  T t_;
};

然后,我们用两个重载替换单个构造函数:一个用于when的隐式构造函数 U 可转换为 T 以及一个显式重载:

template<class T>
struct wrapper {
  template<class U, std::enable_if_t<std::is_convertible_v<U, T>>* = nullptr>
  wrapper(U const& u) : t_(u) {}
  
  template<class U, std::enable_if_t<!std::is_convertible_v<U, T>>* = nullptr>
  explicit wrapper(U const& u) : t_(u) {}

  T t_;
};

这使我们的类型具有所需的行为。然而,这并不是很令人满意:我们现在需要两个重载来实现真正应该是一个的重载,我们使用SFINAE在它们之间进行选择,这意味着我们在编译时间和代码清晰度方面取得了成功。 explicit(bool) 通过允许您将可兑换条件提升到 explicit 说明符:

template<class T> 
struct wrapper { 
  template<class U> 
  explicit(!std::is_convertible_v<U, T>) 
  wrapper(U const& u) : t_(u) {} 

  T t_; 
};

下次需要有条件地显式化某个内容时,请使用 explicit(bool) 对于更简单的代码,更快的编译时间 [3] ,代码重复少。

explicit(bool) 将在MSVC v14.24中受支持 [4] (在Visual Studio 2019版本16.4中提供)、Clang 9和GCC 9。我们希望您 下载Visual Studio 2019 试试看。一如既往,我们欢迎您的反馈。我们可以通过下面的评论或电子邮件联系我们( visualcpp@microsoft.com ). 如果您在使用visualstudio或MSVC时遇到问题,或者有什么建议,请告诉我们 帮助>发送反馈>报告问题/提供建议 在产品中,或通过 开发者社区 . 你也可以在Twitter上找到我们( @视觉 ).

  1. 我知道,隐性转化是邪恶的。不过,在某些地方,它们对人体工程学有了很大的改进,而将选择权留给用户,则使我们的通用类型更为广泛适用。
  2. std::forward 为了简洁起见,省略了这些。
  3. 我用visualstudio2019版本16.2测试了500个模板实例化,并使用 explicit(bool) 将前端速度提高了约15%
  4. MSVC v14.22(visualstudio2019版本16.2)中支持此功能,用于具有/permissive-的生成,但对于不使用该标志的生成,存在一些问题。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享