网站首页 > 博客文章 正文
今天我想谈谈C++ 20的Concept以及它们如何帮助您简化代码。另外,也会让代码更准确。
设想一个类模板,我们希望在其中禁用某个方法。
template<typename T, bool enable = true>
class Sample
{
public:
int DisableThisMethodOnRequest() { return 42; }
};
通常的方法是SFINAE,使用enable_if。
class Sample
{
public:
std::enable_if_t<enable, int> DisableThisMethodOnRequest() { return 42; }
};
好吧,enable_if并不完全满足我的要求,但它看起来简洁易读。遗憾的是,这段代码并没有达到我们想要的效果。SFINAE在这里不适用,因为我们将它应用于方法,而不是类。要使其生效,我们必须使DisableThisMethodOnRequest本身具有模板:
class Sample
{
public:
template<typename Dummy = void>
std::enable_if_t<enable, int> DisableThisMethodOnRequest()
{
return 42;
}
};
为了避免用户必需提供此模板参数,我们将其设置为void作为默认值,并给它一个古怪的名字。希望这样可以对所有用户暗示不要使用这个模板参数。好吧,对初学者来说这可能不太清晰。另外,我们把这个方法作为一个模板,可能引发其他问题。现在,C++ 20很快就会出现在我们的手中。目前,ISO正在评估最终文档。设计已经关闭,所以我们可以安全地假定Concept将在C++ 20中,并且在最新的工作草案中指定。
使用C++20 Concept
Concept在手,我们可以重写前面的示例:
template<typename T, bool enable = true>
class Sample
{
public:
int DisableThisMethodOnRequest() requires(enable) { return 42; }
};
我们可以去掉enable_if,方法不再需要声明为模板。通过简单地在函数声明后面加上一个requires子句,我们可以得到相同的结果。
除开这次简短清晰之外,我个人并不喜欢这种dummy默认模版参数。当使用可以提供类型或方法信息的IDE时,它们对用户是可见的,但实际上它们不是用户应该看到或者关心的。
requires的三个合法位置
requires子句
template<typename T>
requires YourRequirementOrConcept<T>
void func();
后置requires子句
void func() requires YourRequirementOrConcept<T>;
这是我们在示例中使用的版本。这里您可以看到它还可以与模板和模板参数组合使用。
作为限制性模版参数
template<YourRequirementOrConcept T>
void func();
在这里,requires子句嵌入到您的YourRequirementOrConcept中。如果您有一个多次使用的requirement,这可能是最常见的形式。它使您能够为它提供一个合适的名称,以及一个唯一的实现。这里的Concept可以是这样的:
template<typename T>
concept YourRequirementOrConcept = requires SomeThing;
还有更多
有时我们只想提供一个默认的构造函数,只依赖于某些条件。这个例子是一个包装器类型,它应该模拟包装器类型的行为。这是一个启用“如果”的作业。下面是一个例子:
#include <type_traits>
template<bool WithDefaultCtor>
class ClassWithOptionalDefaultCtor
{
public:
template<typename std::enable_if<WithDefaultCtor, int>::type = 0>
ClassWithOptionalDefaultCtor() // 1 we cannot say =default here
{
}
};
int main()
{
ClassWithOptionalDefaultCtor<true> t{};
}
注意,在//1处我们不能使用=default,因为这不是默认构造函数。它是一个看起来像默认构造函数的方法模板。这样的事情不能默认,因为编译器不知道它是什么。如果不将变量添加到构造函数初始值设定项列表中,上面的非常糟糕的解决方案会导致未初始化的变量。假设我们讨论的是包装器,它可能只有一个成员值。添加此成员并不麻烦。只是这个解决方案似乎不是很通用。
C++ 20可以让我们将代码改写为:
template<bool WithDefaultCtor>
class ClassWithOptionalDefaultCtor
{
public:
ClassWithOptionalDefaultCtor() requires(WithDefaultCtor) =
default; // 1 way better
};
int main()
{
ClassWithOptionalDefaultCtor<true> t{};
}
漂亮的代码!首先请注意,type_traits include连同丑陋的enable_if一起消失了。仅此一项就带来了编译时的加速,是否显著则是另一个问题。如果requires条件变得更复杂并且需要其他概念,编译加速也可能反转。
与前面的示例一样,我认为requires子句使代码更具可读性。但最棒的是我们现在可以使用=default!有了C++ 20的Concept,我们可以在这里拥有一个真正的默认构造函数。
猜你喜欢
- 2024-10-12 C++核心准则T.24:用标签类或特征区分只有语义不同的概念
- 2024-10-12 用苹果发布会方式打开C++20(苹果在哪开发布会)
- 2024-10-12 C++核心准则T.25:避免互补性约束(规矩是一种约束,一种准则)
- 2024-10-12 C++核心准则T.21:为概念定义一套完整的操作
- 2024-10-12 C++核心准则T.5:结合使用泛型和面向对象技术应该增强效果
- 2024-10-12 C++经典书籍(c++相关书籍)
- 2024-10-12 C++一行代码实现任意系统函数Hook
- 2024-10-12 C++核心准则T.11:只要可能就使用标准概念
- 2024-10-12 C++核心准则T.48:如果不能用概念,用enable_if
- 2024-10-12 C++核心准则T.13:简单、单类型参数概念使用缩略记法更好
你 发表评论:
欢迎- 最近发表
-
- 给3D Slicer添加Python第三方插件库
- Python自动化——pytest常用插件详解
- Pycharm下安装MicroPython Tools插件(ESP32开发板)
- IntelliJ IDEA 2025.1.3 发布(idea 2020)
- IDEA+Continue插件+DeepSeek:开发者效率飙升的「三体组合」!
- Cursor:提升Python开发效率的必备IDE及插件安装指南
- 日本旅行时想借厕所、买香烟怎么办?便利商店里能解决大问题!
- 11天!日本史上最长黄金周来了!旅游万金句总结!
- 北川景子&DAIGO缘定1.11 召开记者会宣布结婚
- PIKO‘PPAP’ 洗脑歌登上美国告示牌
- 标签列表
-
- ifneq (61)
- messagesource (56)
- aspose.pdf破解版 (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- vue数组concat (56)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)