C++ 模板:以简御繁-4/5

Dev-Cpp 5.5.3 + MinGW 4.7.2 一站式C++开发环境安装与实战 Dev-Cpp 5.5.3 是基于 Windows 平台的轻量级 C/C++ 集成开发环境,采用Scintilla作为代码编辑引擎,具备语法高亮、自动补全和代码折叠等现代编辑功能。其界面简洁直观,适合初学者快速上手,同时支持项目管理与调试集成,满足中级开发者需求。要在 Dev-Cpp 中启用 C++11,必须手动添加编译标志。进入:在“Additional command line options”输入框中添加:-std=c++11。 阅读详情

 英文原文:https://victor-istomin.github.io/c-with-crosses/posts/templates-are-easy/

C++ 模板:以简御繁-1/5

C++ 模板:以简御繁-2/5

C++ 模板:以简御繁-3/5

C++ 模板:以简御繁-4/5

C++ 模板:以简御繁-5/5

9. 概念:一种设置模板类型要求的现代方法

现在是时候做出转变了:使用 C++20,我们可以避免编写 SFINAE 代码并接受概念

概念(concept)是一组命名的需求。cppreference 上有一篇详细的文章,但其要点如下:它允许根据模板参数区分多个模板重载,类似于 SFINAE。然而,概念通过将声明与使用分离,并允许更简单的组合,增强了清晰度,从而使代码更简洁。

9.1 一个简单的基于特征的概念和一个要求

让我们对 makeString(String&& s) 和 makeString(Numeric value) 重载进行最小的修改,并看一下第一次尝试:

namespace traits
{
template <typename T> 
inline constexpr bool isString = std::is_constructible_v<std::string, T>;
}

// a concepts that uses a constexpr bool trait to check its applicability
template <typename T>
concept IsString = traits::isString<T>;

template <IsString String>
std::string makeString(String&& s) 
{
    return std::string(std::forward<String>(s));
}

// a concept uses requires clause: code in braces should compile
template <typename T>
concept HasStdConversion = requires (T number) { std::to_string(number); };

std::string makeString(HasStdConversion auto number)
{
    return std::to_string(number);
}

第9行:创建了一个简单概念,用于演示 constexpr bool 作为必要条件的用法。虽然 <concepts> 提供了 std::constructible_from 接口,但我们将使用一个基于自定义 trait 的概念作为展示。

第11-12行:使用 IsString 概念代替 typename 关键字,以尽量减少代码编写。请注意,不再需要 SFINAE 或尾随返回类型。

第19行引入了一个必要条件:HasStdConversion 是一个概念,它要求使用 T 函数 number 编译 std::to_string(number); 以确保 std::to_string 转换存在。这仍然不是什么高深的学问。

第21行:使用 HasStdConversion 来约束参数的 auto 类型。这种方法与第11-12行的方法等效,并且所需的绑定更少。但是,考虑到代码清晰度,我个人倾向于使用 template 关键字来清楚地表明以下方法是模板。

9.2 概念:合取和析取

现在,可以使用 <concepts> 来进一步简化代码,而无需手写 trait。此外,删除 trait 命名空间,并使用概念重写每个函数声明,而不是声明。如下所示

假设类型 T 是一个字符串,如果 std::string 是 std::constructible_from 它:

template <typename T>
concept IsString = std::constructible_from<std::string, T>;

template <IsString String>
std::string makeString(String&& s) 
{
    return std::string(std::forward<String>(s));
}

HasStdConversion 将要求可以在其参数上调用 std::to_string

template <typename T>
concept HasStdConversion = requires (T number) { std::to_string(number); };

template <HasStdConversion Numeric>
std::string makeString(Numeric number)
{
    return std::to_string(number);
}

HasToString 是一个概念,它要求 object.to_string() 函数以 Object 对象为参数,且返回 std::convertible_to<std::string> 类型的值。在这种情况下,除了编译括号内代码的基本要求外,还会使用另一个概念来检查表达式的类型。

template <typename T>
concept HasToString = requires (T&& object) 
{ 
    {object.to_string()} -> std::convertible_to<std::string>; 
};

template <HasToString Object>
std::string makeString(Object&& object) 
{
    return std::forward<Object>(object).to_string();
}

最后,棘手的部分。与 SFINAE 方法类似,IsContainer 要求类型可迭代:requires (T&& container) { std::begin(container); }。然而,字符串本身也是容器,这会导致调用 makeString("hello") 时出现歧义,因为两个重载都会匹配。在我们的代码中,requires 子句在要求布尔约束时很有用。

template <typename T>
concept IsContainer = requires (T&& container) { std::begin(container); };

template <typename Iterable>
    requires (IsContainer<Iterable> && !IsString<Iterable>)
std::string makeString(Iterable&& iterable) 
{
    //...
}

不过,我更倾向于将 IsContainer 定义为可迭代对象,将 IsString 定义为可用于构造 std::string 的 IsContainer。这样,当某个对象同时满足 IsString 和 IsContainer 两个条件时,前者将具有优先权,因为编译器会优先考虑约束更严格的那个。

这些都是很棒的文章,深入解释了合取、析取和按约束排序,我强烈建议您看一下。

也许,通过提供完整的源代码来总结代码并与读者的想象力同步是一个好主意:

// makeString.hpp
#pragma once
#include <string>
#include <type_traits>
#include <concepts>

template <typename T>
concept IsContainer = requires (T&& container) { std::begin(container); };

// IsString is more constrained than IsContainer, 
// so it will have a priority wherever possible
template <typename T>
concept IsString = IsContainer<T> && std::constructible_from<std::string, T>;

template <typename T>
concept HasStdConversion = requires (T number) { std::to_string(number); };

template <typename T>
concept HasToString = requires (T&& object) 
{ 
    {object.to_string()} -> std::convertible_to<std::string>; 
};


template <HasStdConversion Numeric>
std::string makeString(Numeric number)
{
    return std::to_string(number);
}

template <HasToString Object>
std::string makeString(Object&& object) 
{
    return std::forward<Object>(object).to_string();
}

template <IsString String>
std::string makeString(String&& s) 
{
    return std::string(std::forward<String>(s));
}

template <IsContainer Iterable>
std::string makeString(Iterable&& iterable) 
{
    std::string result;
    for (auto&& i : iterable)
    {
        if (!result.empty())
            result += ';';

        // a constexpr if, so the compiler can omit unused branch and
        // allow non-copyable types usage
        if constexpr (std::is_rvalue_reference_v<decltype(iterable)>)
            result += makeString(std::move(i));
        else 
            result += makeString(i);
    }
    return result;
}

编译、运行:成功了!

9.3 按约束对重载进行排序

说到可扩展性,假设我们的 makeString 是一个库头文件,我们不愿意修改它。在这种情况下,考虑一下同时具有 IsContainer 和 HasToString 属性的类:

struct C
{
    std::string m_string;
  
    auto begin() const { return std::begin(m_string); }
    auto begin()       { return std::begin(m_string); }
    auto end() const   { return std::end(m_string); }
    auto end()         { return std::end(m_string); }

    std::string to_string() const { return "C{\"" + m_string + "\"}"; }
};

int main()
{
    // ...
    std::cout << makeString(makeVector())
              << std::endl
              << makeString( C { "a container with its own to_string()" } )
              << std::endl;

}

makeString(C{...}) 调用中存在歧义,因为编译器无法确定 IsContainer 或 HasToString 重载是否更适合应用。

[build] main.cpp:58:18: error: call to 'makeString' is ambiguous
[build]               << makeString( C { "a container with its own to_string()" } )
[build]                  ^~~~~~~~~~
[build] makeString.hpp:37:13: note: candidate function [with Object = C]
[build] std::string makeString(Object&& object) 
[build]             ^
[build] makeString.hpp:49:13: note: candidate function [with Iterable = C]
[build] std::string makeString(Iterable&& iterable) 
[build]             ^

熟悉 SFINAE 时代的人可以想象这场悲剧的严重性,而那些已经看过 Andrzej 关于按约束排序的文章的人可以想象解决方案。

歧义的产生是因为两个受约束的方法具有相同的优先级,并且彼此之间没有任何约束可以包含对方。解决方案很简单:引入第三个重载,使其比冲突的重载更具限制性。

struct C
{
    std::string m_string;
  
    auto begin() const { return std::begin(m_string); }
    auto begin()       { return std::begin(m_string); }
    auto end() const   { return std::end(m_string); }
    auto end()         { return std::end(m_string); }

    std::string to_string() const { return "C{\"" + m_string + "\"}"; }
};

template <typename Container>
    requires IsContainer<Container> && HasToString<Container>
std::string makeString(Container&& c)
{
    return std::forward<Container>(c).to_string();
}

int main()
{
    // ...
    std::cout << makeString(makeVector())
              << std::endl
              << makeString( C { "a container with its own to_string()" } )
              << std::endl;
}

这样,通过引入新规则解决了歧义问题,保留了库的实现

SAP CBC 集成质量系统初始化接入实战指南 摘要 本文探讨了SAP S/4HANA Cloud Public Edition项目中质量系统的初始接入过程。质量系统并非开箱即用,而是需要经过SAP Central Business Configuration(CBC)的Scope and Organizational Structure阶段部署后才能具备完整功能。文章重点分析了几个关键环节:CBC里程碑确认的时机选择、Identity Authentication的初始管理员设置、Business Role Template的创建规范等。实施过程中需特 阅读详情

相关推荐

写给小白的“具身智能”入门科普

智能”,大家都懂,也就是AI。那么,什么是“具身”?“具身”是一个很小众的名词,通常都出现在哲学、认知科学领域。它的英文叫Embodied,是embody的过去式和过去分词。em-表示“进入,使……”,-body表示“身体”。组合起来,就是“使……进入身体”。Embodied Intelligence(具身智能),顾名思义,就是“使智能进入身体”、“给智能一个身体”的意思。那么,具身智能,是不是就是“AI+身体”呢?这样说并不准确。

欢迎来到我的博客 1820

C++ 模板:以简御繁-5/5

可变参数模板

immigrator的专栏 878

ESP32 CAM安装配置 第四部份:通过使用ESPHome的方式ESP32 Cam加到HomeAssistant

这些包括 aec_value, aec2, ae_level, agc_gain, gain_ctrl, bpc, wpc, raw_gma, lenc, hmirror, dcw, colorbar 等。这些参数的可能值和具体效果会根据你的摄像头硬件和 ESPHome 的版本有所不同。在 ESPHome 中配置 ESP32 Cam 时,每个参数的可能值取决于具体的功能和支持范围。值的范围是 0 到 63,其中 0 是最差质量,63 是最佳质量。horizontal: 水平校正的强度,通常是一个数字值。

weixin_42895252的博客 3364

C++ 模板:以简御繁-1/5

英文原文:这篇系列文章从一个简单的需求开始,介绍了如何一步一步,从简到繁用模板来实现,仔细阅读,你一定会有收获。想象一下有一种能力将所有内容转换为字符串:整数、向量、布尔值 - 所有这些都被转换成一条信息,以输出到我们想要的任何地方。这个要求看起来很方便,也不太难,所以让我们深入研究它——这是我为我的宠物项目编写调试变量观察器时的第一个想法。尽管期望让事情变得简单可能会导致几个不眠之夜,但我还是鼓励读者通过基本的模板编程概念踏上这段旅程。

immigrator的专栏 69

Innovus Flexible H-tree and Multi-tap Clock Flow Lab实操系列教程(Day1)

Innovus Flexible H-tree and Multi-tap Clock Flow Lab实操系列教程(Day1)

weixin_37584728的博客 2637

使用STM32制作智能窗帘控制

以上就是一个简单的基于STM32的智能窗帘控制代码案例。通过感知光线强度和控制步进电机的旋转,我们可以实现智能窗帘的自动开启和关闭。通过定时器的中断来控制步进电机的旋转,从而实现窗帘的开启和关闭动作。最后,我们需要实现主函数和中断函数。在主函数中,我们需要初始化硬件资源,然后进入一个无限循环来不断检测光敏电阻的值,并根据其值来控制窗帘的开启和关闭。接下来,我们需要编写功能函数,用于控制窗帘的开启和关闭。然后,我们需要配置STM32开发环境,并创建一个新的工程。接下来,我们初始化相关的硬件资源。

2401_85258012的博客 276

C++ 模板:以简御繁-2/5

Type traits用法

immigrator的专栏 93

软考「系统规划与管理师(第2版)」通关全攻略(2026年下半年)

它考的是一个IT管理者能不能用体系化的语言,把"我们为什么要建这个系统→怎么规划→怎么管好服务→怎么合规"讲圆。所以备考的核心策略也很明确——教材建框架 → 真题磨考点 → 案例练结构 → 论文备好真实项目素材 → 机考练打字。按计划走,不贪全、不盲刷、不死背,稳稳把三科都推过45分那条线。祝你通关 🎯。

软件行业技术文化交流。 3042

C++ 模板:以简御繁-3/5

完美转发

immigrator的专栏 74

微信小程序 - 解决报错 operateAudio:fail audioInstance is not set(wx.getRecorderManager苹果ios真机调试运行,播放音频播放出错解决)

微信小程序,苹果ios系统,真机测试报错,播放音频报错operateAudio:fail audioInstance not exist,errCode: -1,小程序生成音频播放报错errMsg,真机调试报错开发者工具没问题,wx.getRecorderManager,音频实例,InnerAudioContext,各种方法都试了不行,只有ios苹果手机有这个问题,IOS 出现 operateAudio,在iOS无法播放的解决方案,更新到最新版本了还是不行,链接没有特殊字符,微信小程序全局音频设置,手机上播

🏆 前端领域优质创作者 1万+

UE5、CesiumForUnreal实现加载GeoJson绘制多面(MultiPolygon)功能(支持点选高亮)

UE5、CesiumForUnreal实现加载GeoJson实现多面(MultiPolygon)的绘制功能,并且支持点选高亮和属性查询。

专注GIS开发 4628

C++:模板总结

写在前面 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream。模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成...

现从事游戏开发领域 | 团队项目be_with开发进行中 web方向感兴趣者私 ——We can do all things. 6万+

【Mode Management】AUTOSAR架构下RH850-F1KM芯片深度休眠配置实践

AUTOSAR架构下RH850-F1KM芯片深度休眠配置实践

qq_36056498的博客 1088

C++模板(函数模板/类模板)

Ⅰ、编程 Ⅱ、函数模板 1、函数模板概念 2、函数模板格式 3、函数模板的原理 4、函数模板的实例化 1.隐式实例化 2.显示实例化 5、模板参数的匹配原则 ​编辑补充:函数不一定都能推演,但是类模板一定要指定 Ⅲ、类模板 1、类模板的定义格式 2、类模板的实例化 3、类外定义类模板参数 4、模板的分离编译......

qq_61386381的博客 1万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

RedPanda-CPP项目模板使用技巧:快速创建专业C/C++工程

RedPanda-CPP是一款基于Qt开发的轻量级C/C++集成开发环境(IDE),它提供了丰富的项目模板功能,帮助开发者快速搭建专业的C/C++工程。本文将详细介绍如何充分利用RedPanda-CPP的项目模板,提升开发效率,让你轻松创建规范的C/C++项目。 ## 为什么使用项目模板? 项目模板是RedPanda-CPP的核心功能之一,它能够: - 提供标准化的项目结构,确保代码组织一致性

gitblog_01423的博客 866

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

【C++】模板进阶:深入解析模板特化

本章将深入探讨模板的高级应用,重点解析模板特化的概念和实现方法。

专注于 C/C++ 后端开发,涵盖基础语法、Linux系统与网络、MySQL数据库、常见算法及项目经验。 2520

【C++】—— 模板进阶

C++模板

yusjushd的博客 2646

【亲测免费】 探索编程之旅:Dev-cpp 5.4.0 —— 经典C/C++开发工具回归!

探索编程之旅:Dev-cpp 5.4.0 —— 经典C/C++开发工具回归! 去发现同类优质开源项目:https://gitcode.com/ 在编程的世界里,有一款经典而高效的轻量级开发环境——Dev-cpp 5.4.0,它如同一位默默无闻的导师,引导着一代又一代编程新人踏入C/C++的大门。今天,我们特别为您带来这份宝藏工具及其详尽的API帮助文档,旨在让每一位学习者和开发者都能轻松上手,高效...

gitblog_06517的博客 964

【CPP】C++模板:初阶到进阶语法与实用编程示例

探索C++模板的深度与广度,《C++模板:初阶到进阶语法与实用编程示例》带您从基础语法起步,逐步深入到高级特性。本博客结合精炼的理论知识和丰富的代码实例,揭示模板编程的精髓,助您提升开发效率,优化代码结构。无论您是初学者还是资深开发者,都能在这里找到提升C++编程技能的宝贵资源。

BinaryWiker的博客 1380

C++模板—函数模板、类模板

C++函数模板、类模板

Han同学 1672

【C++】C++11可变参数模板(函数模板、类模板)

在C++11之前,类模板和函数模板只能含有固定数量的模板参数。C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。可变参数模板的加入使得C++11的功能变得更加强大,而由此也带来了许多神奇的用法。 本文实例源码github地址:https://github.com/yngzMiao/yngzmiao-blogs/tree/master/2020Q2/20200401...

Yngz_Miao的博客 3万+

5个高效配置让Dev-CPP成为C/C++编程入门利器

Dev-CPP是一款轻量级C/C++集成开发环境,通过优化的代码编辑界面、智能补全功能和便捷的项目管理系统,为编程学习者和初级开发者提供了高效的开发体验。该工具在经典Dev-C++基础上进行了深度重构,保留了轻量特性的同时增强了现代化开发功能,特别适合C/C++初学者快速掌握编程基础。 ## 一、基础配置篇:从零开始搭建开发环境 ### 编译器安装与验证 **问题现象**:首次启动程序时出现

gitblog_00692的博客 331

cpp之模板

这里只针对模板对于一些数组或者类作为参数的情况,函数模板无法正确运行了;我们可以运用以前学过的运算符重载,不过那会显得非常麻烦,所以这里就有了函数模板的重载,即提供一个具体化的模板。如果是全局函数在类内实现友元函数那么直接实现就可以了,但是如果是在类外实现友元函数,我们需要提前让编译器知道全局函数的存在。,这和之前的默认函数参数规则是一样的,不过要注意的是如果我们全部使用了默认参数也要在调用时写上空列表即。不仅要告知编译器模板参数的存在,还要告知其不为普通函数的类外实现,而是函数模板的类外实现。

2303_80883523的博客 1509

godot-cpp跨版本兼容性:从4.0到4.5的迁移要点

你是否在将Godot项目从4.0升级到最新4.5版本时遇到兼容性问题?本文将系统梳理godot-cpp从4.0到4.5的核心变更点,帮助开发者平稳完成迁移。读完本文你将掌握:版本匹配策略、API重大变更、构建配置升级及常见问题解决方案。 ## 版本匹配基础 godot-cpp采用与Godot引擎严格对应的版本管理策略。项目的`master`分支仅兼容Godot主开发分支,稳定版本需使用对应分支...

gitblog_00194的博客 1157

【C++模板进阶】——【非类型模板参数 / 模板的特化 / 模板分离编译】

本文深入探讨C++模板编程的两个重要特性:非类型模板参数和模板特化。非类型模板参数允许在编译期指定常量值,用于创建固定大小的数组等场景。

枫亭湖区的博客 3220

Dev-Cpp5.11版本Dev-c安装包:编程利器,轻松掌握C/C++开发

Dev-Cpp5.11版本Dev-c安装包:编程利器,轻松掌握C/C++开发 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 Dev-Cpp 5.11版本安装包为您提供了一种简单快捷的方式来安装和使用Dev-C++。Dev-C++(又称Dev-Cpp)是一款广受欢迎的免费集成开发环境(IDE),它专为C/C++编程语言而设计。这个安装包包含了2020年5月的最新版Dev...

gitblog_06729的博客 1001

终极指南:如何用Dev-CPP快速上手C/C++开发

你是否正在寻找一款轻量级但功能强大的C/C++集成开发环境?Dev-CPP正是为你量身打造的解决方案。这个开源项目不仅完全免费,还提供了从代码编辑到编译调试的一站式开发体验,特别适合初学者和中小型项目开发。在接下来的内容中,我将带你深入了解这个高效IDE的方方面面。 ## 🚀 快速入门:你的第一个C++程序 ### 为什么选择Dev-CPP作为起点? 对于C/C++新手来说,选择一个合适的开

gitblog_00667的博客 799
上一篇: C++ 模板:以简御繁-3/5
下一篇: C++在变态之路上一路狂奔
SONG_CA
博客等级 码龄24年 74粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值