IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 参数包 -> 正文阅读

[C++知识库]C++ 参数包

简介

模板参数包是可以接受零个或多个模板参数(非类型、类型或模板)的模板参数。

1. 语法

(1) 非类型模板参数包:

ConcreteType... Args

此处 ConcreteType 为具体的类型,如 int.

(2) 类型模板参数包:

typename... Types

(3) 模板模板参数包:(即模板形参是另一个模板)

template <parameter-list> typename... Types

(4) 参数包扩展:

pattern...

pattern 扩展为以逗号分隔的列表(包含0或多个模式). 其中,pattern 必须包含至少一个参数包.

在类模板中,模板参数包需是最后一个模板形参. 而在函数模板中则不必(指的是在模板形参列表中的位置,而不是函数形参列表),只要能够从函数实参列表推断出参数包即可.

template<typename... Ts, typename U> struct Invalid; // Error: Ts.. not at the end
 
template<typename... Ts, typename U, typename=void>
void valid(U, Ts...);     // OK: can deduce U
// void valid(Ts..., U);  // Can't be used: Ts... is a non-deduced context in this position

从上例中可以看出,即使是在函数模板中,参数包仍需要是函数形参列表的最后一个参数. 简单起见,尽量将参数包放在最后.

例子1:

template<typename... Ts>	// (2)
void f(Ts...) {}			// (4)
template<typename... Ts, int... N>		// (2),(1)
void g(Ts (&...arr)[N]) {}				// (4)

int n[1];
g<const char, int>("a", n); // Ts (&...arr)[N] expands to 
                            // const char (&)[2], int(&)[1]

注意:不允许使用 Ts (&...)[N],因为 C++11 语法要求圆括号括起的 ... 需要有一个名字.

例子2:

#include <iostream>

void myPrintf(const char* fmt)
{
	std::cout << fmt;
}

template <typename T, typename... Ts>
void myPrintf(const char* fmt, T value, Ts... args)
{
	for (; *fmt != '\0'; fmt++)
	{
		if (*fmt == '%')
		{
			std::cout << value;

			myPrintf(fmt+1, args...);
			return;
		}

		std::cout << *fmt;
	}
}

int main()
{
	myPrintf("Hello, I'm %, % yeas old.", "gzming", 20);
}
Hello, I'm gzming, 20 yeas old.

2. 参数包扩展

  • pattern 中包含多个参数包时,这些参数包的长度应该一致.

    template<typename...> struct Tuple {};
    template<typename T1, typename T2> struct Pair {};
    
    template<class ...Args1> struct zip 
    {
        template<class ...Args2> struct with 
        {
            typedef Tuple<Pair<Args1, Args2>...> type;      // Pair<Args1, Args2> is the pattern
        };
    };
    
    typedef zip<short, int>::with<unsigned short, unsigned>::type T1;
    
  • 当参数包嵌套时,内层的参数包先扩展,然后再和外层的参数包一起扩展.

    template<class... Args>
    void g(Args... args) 
    {
    	/*
    	inner pack expansion is "args...", it is expanded first
    	outer pack expansion is h(E1, E2, E3) + args..., it is expanded
    	second (as h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3)
    	*/
        f(h(args...) + args...);
    }
    

参数包扩展可在如下地方使用

  • 模板形参列表

    template<typename... T>
    struct value_holder
    {
        template<T... Values> // expands to a non-type template parameter list,
        struct apply {};     // such as <int, char, int(&)[5]>
    };
    
  • 模板实参列表

    template<class A, class B, class...C>
    void func(A arg1, B arg2, C...arg3)
    {
        container<A, B, C...> t1; 
        container<C..., A, B> t2; 
        container<A, C..., B> t3;
    }
    
  • 函数形参列表

    template<typename ...Ts>
    void f(Ts...) {}
    
  • 函数实参列表

    f(&args...);
    f(++args..., n);
    
    // f(const_cast<const E1*>(&X1), const_cast<const E2*>(&X2), const_cast<const E3*>(&X3))
    f(const_cast<const Args*>(&args)...);
    
  • 圆括号初始化器

    Class c1(&args...);
    
  • 花括号初始化器

    template<typename... Ts> void func(Ts... args) {
        const int size = sizeof...(args) + 2;
        int res[size] = { 1,args...,2 };
    }
    

    sizeof... 运算符返回参数包的大小.

  • 基类列表、成员初始化列表

    template<class... Mixins>
    class X : public Mixins... {
     public:
        X(const Mixins&... mixins) : Mixins(mixins)... { }
    };
    
  • Lambda 捕获

    template<class... Args>
    void f(Args... args) {
        auto lm = [&, args...]{ return g(args...); };
        lm();
    }
    
  • sizeof... 运算符

    template<class... Types>
    struct count {
    	static const std::size_t n = sizeof...(Types);
    };
    
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-11 18:37:21  更:2021-09-11 18:39:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 13:52:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计