explicit(bool)
是C++ 20的特性,用于简化泛型类型的实现和提高编译时性能。
在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上找到我们( @视觉 ).