400 028 6601

建站动态

根据您的个性需求进行定制 先人一步 抢占小程序红利时代

C++模板(第二版)笔记之第四章:变参模板-创新互联

文章目录

创新互联建站坚持“要么做到,要么别承诺”的工作理念,服务领域包括:做网站、成都网站设计、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的杭州网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!一、变参模板 1.变参模板eg

可以将模板参数定义成能够接受任意多个模板参数的情况。 这一类模板被称为变参模板(variadic template)。

#include//为了结束递归, 重载了不接受参数的非模板函数 print(), 它会在参数包为空的时候被调用。
void print ()
{}

//这些被称为 args的剩余参数, 是一个函数参数包(function parameter pack) :
templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< '\n' ; //print first argument
    print(args…); // call print() for remaining arguments
}


int main()
{std::string s("world");
    print (7.5, "hello", s);
}
7.5
hello
World

解释:

print(7.5, “hello”, s);
其中:
firstArg 的值是 7.5, 其类型 T 是 double。
args 是一个可变模板参数, 它包含类型是 char const*的“hello” 和类型是 std::string 的“world”

print(“hello”, s);
其中:
firstArg 的值是“hello” , 其类型 T 是 char const *。
args 是一个可变模板参数, 它包含的参数类型是 std::string。

其中:
firstArg 的值是“world” , 其类型 T 是 std::string。
args 是一个空的可变模板参数, 它没有任何值

2.变参和非变参模板的重载
#include//为了结束递归, 重载了不接受参数的非模板函数 print(), 它会在参数包为空的时候被调用。
templatevoid print (T arg)
{std::cout<< arg<< '\n' ; //print passed argument
}

//这些被称为 args的剩余参数, 是一个函数参数包(function parameter pack) :
templatevoid print (T firstArg, Types... args)
{std::cout<< firstArg<< '\n' ; //print first argument
    print(args...); // call print() for remaining arguments
}
#includetemplatevoid print(T arg)
{(std::cout<< arg)<< '\n';
}
int main()
{std::cout<< "Hello World";
    print();
    return 0;
}
/home/insights/insights.cpp:10:5: error: no matching function for call to 'print'
    print();
    ^~~~~
/home/insights/insights.cpp:3:6: note: candidate function template not viable: requires single argument 'arg', but no arguments were provided
void print(T arg)
     ^
1 error generated.
Error while processing /home/insights/insights.cpp.
3.sizeof… 运算符

C++11 为变参模板引入了一种新的 sizeof 运算符: sizeof…。 它会被扩展成参数包中所包含的参数数目。

templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< ’ \n’ ; //print first argument
	std::cout<< sizeof…(Types)<< ’ \n’ ; //print number of remaining
	types
	std::cout<< sizeof…(args)<< ’ \n’ ; //print number of remainingargs
…
}
templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< ’ \n’ ;
	if (sizeof…(args) >0) {//error if sizeof…(args)==0
		print(args…); // and no print() for no arguments declared
	}
}

解释:

templatevoid print (T firstArg, Types… args)
{std::cout<< firstArg<< ’ \n’ ;
	if constexpr(sizeof…(args) >0) {print(args…); //code only available if sizeof…(args)>0 (sinceC++17)
	}
}

解释:

二、折叠表达式

从 C++17 开始, 提供了一种可以用来计算参数包(可以有初始值) 中所有参数运算结果的二元运算符。

templateauto foldSum (T… s) {return (… + s); // ((s1 + s2) + s3) …
}

更好的方法

templateauto sum(T ...t)
{return (0+...+t);
}
// define binary tree structure and traverse helpers:
struct Node {int value;
	Node* left;
	Node* right;
	Node(int i=0) : value(i), left(nullptr), right(nullptr) {}
};

auto left = &Node::left;
auto right = &Node::right;
// traverse tree, using fold expression:
templateNode* traverse (T np, TP… paths) 
{//折叠表达式从 np 开始遍历了 paths 中所有可变成员。
	return (np ->* … ->* paths); // np ->* paths1 ->* paths2 …
}

int main()
{// init binary tree structure:
	Node* root = new Node{0};
	root->left = new Node{1};
	root->left->right = new Node{2}; 
	//traverse binary tree:
	Node* node = traverse(root, left, right);
}
templateclass AddSpace
{private:
	T const& ref; // refer to argument passed in constructor
public:
	AddSpace(T const& r): ref(r) {}

friend std::ostream& operator<< (std::ostream& os, AddSpaces) 
{return os<< s.ref<<’ ’ ; // output passed argument and a space
}
};

templatevoid print (Args… args) {( 
	std::cout<< …<< AddSpace(args) )<< ’ \n’ ;
}

//更好的方法
templatevoid print(T0 const &t0, T const &...t) {std::cout<< t0;
    ((std::cout<< ' '<< t), ...);
    std::cout<< std::endl;
}
三、变参模板的使用

一个重要的作用是转发任意类型和数量的参数。

通常是使用移动语义对参数进行完美转发(perfectly forwarded)

注意, 之前关于常规模板参数的规则同样适用于变参模板参数。

// args are copies with decayed types:
templatevoid foo (Args… args);
// args are nondecayed references to passed objects:
templatevoid bar (Args const&… args);
四、变参类模板和变参表达式

参数包还可以出现在其它一些地方, 比如表达式, 类模板, using 声明, 甚至是推断指引中。

1.变参表达式
templatevoid printDoubled (T const&… args)
{print (args + args…);
}

如果这样调用它:
printDoubled(7.5, std::string("hello"), std::complex(4,2));

效果上和下面的调用相同(除了构造函数方面的不同) :
print(7.5 + 7.5, std::string("hello") + std::string("hello"),
std::complex(4,2) + std::complex(4,2);
templatevoid addOne (T const&… args)
{print (args + 1…); // ERROR: 1… is a literal with too many decimal points
print (args + 1 …); // OK
print ((args + 1)…); // OK
}
templateconstexpr bool isHomogeneous (T1, TN…)
{return (std::is_same::value && …); // since C++17
}

对于:
isHomogeneous(43, -1, "hello")
会被扩展成:
std::is_same::value && std::is_same::value
结果自然是 false。 

而对:isHomogeneous("hello", "", "world", "!")
结果则是 true, 因为所有的参数类型都被推断为 char const *( 这里因为是按值传递, 所以
发生了类型退还, 否则类型将依次被推断为: char const[6], char const[1], char const[6]和 char const[2]) 。

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


网页名称:C++模板(第二版)笔记之第四章:变参模板-创新互联
文章地址:http://www.bluegullmedia.com/article/ddhjcp.html

其他资讯

让你的专属顾问为你服务

0.1955s