您的位置:首页 > 编程语言 > C语言/C++

省略号和可变参数模板

2016-07-18 00:00 323 查看
省略号和可变参数模板 https://msdn.microsoft.com/zh-cn/library/dn439779.aspx
This article shows how to use the ellipsis(省略号) (...) with C++ variadic templates.The ellipsis has had many uses in C and C++.These include variable argument lists for functions.The printf() function from the C Runtime Library is one of the most well-known examples.

A variadic template is a class or function template that supports an arbitrary number of arguments.This mechanism is especially useful to C++ library developers because you can apply it to both class templates and function templates, and thereby provide a wide range of type-safe and non-trivial functionality and flexibility.

Syntax

An ellipsis is used in two ways by variadic templates.To the left of the parameter name, it signifies(表示) a parameter pack(note:这里pack是名词), and to the right of the parameter name, it expands the parameter packs into separate names.(??????)

Here's a basic example of variadic template class definition syntax:

C++

template<typename... Arguments> class classname;

For both parameter packs and expansions, you can add whitespace around the ellipsis, based on your preference, as shown in these examples:

C++

template<typename ...Arguments> class classname;

Or this:

C++

template<typename ... Arguments> class classname;   //空格可以随便加。

Notice that this article uses the convention(做法) that's shown in the first example (the ellipsis is attached to typename).

常见的做法是将省略号和类型名连在一起。

In the preceding examples, Arguments is a parameter pack.The class classname can accept a variable number of arguments, as in these examples:

C++

template<typename... Arguments> class vtclass;

vtclass< > vtinstance1;
vtclass<int> vtinstance2;
vtclass<float, bool> vtinstance3;
vtclass<long, std::vector<int>, std::string> vtinstance4;

By using a variadic template class definition, you can also require at least one parameter:

通过在parameter pack左边加一个不带省略号的参数来实现

C++

template <typename First, typename... Rest> class classname;

Here's a basic example of variadic template function syntax:

C++

template <typename... Arguments> returntype functionname(Arguments... args);

The Arguments parameter pack is then expanded for use, as shown in the next section, Understanding variadic templates.

Other forms of variadic template function syntax are possible—including, but not limited to, these examples:

C++

template <typename... Arguments> returntype functionname(Arguments&... args);
template <typename... Arguments> returntype functionname(Arguments&&... args);   //右值引用。
template <typename... Arguments> returntype functionname(Arguments*... args);

Specifiers(限定符) like const are also allowed:

C++

template <typename... Arguments> returntype functionname(const Arguments&... args);

As with variadic template class definitions, you can make functions that require at least one parameter:

C++

template <typename First, typename... Rest> returntype functionname(const First& first, const Rest&... args);

Variadic templates use the sizeof...() operator (unrelated to the older sizeof() operator):

C++

template<typename... Arguments>
void tfunc(const Arguments&... args)
{
const unsigned numargs = sizeof...(Arguments);   //unsigned后面没有指定类型,默认是int

X xobj[numargs]; // array of some previously defined type X

helper_func(xobj, args...);
}

More about ellipsis placement

Previously, this article described ellipsis placement that defines parameter packs and expansions as "to the left of the parameter name, it signifies a parameter pack, and to the right of the parameter name, it expands the parameter packs into separate names".This is technically true but can be confusing in translation to code. Consider:

In a template-parameter-list (template <parameter-list>), typename... introduces a template parameter pack.

In a parameter-declaration-clause (func(parameter-list)), a "top-level" ellipsis introduces a function parameter pack, and the ellipsis positioning is important:
C++
// v1 is NOT a function parameter pack:
template <typename... Types> void func1(std::vector<Types...> v1);

// v2 IS a function parameter pack:
template <typename... Types> void func2(std::vector<Types>... v2);


Where the ellipsis appears immediately after a parameter name, you have a parameter pack expansion.

A good way to illustrate(描述) the variadic template function mechanism is to use it in a re-write of some of the functionality of printf:

C++

#include <iostream>

using namespace std;

void print() {
cout << endl;
}

template <typename T> void print(const T& t) {
cout << t << endl;
}

template <typename First, typename... Rest> void print(const First& first, const Rest&... rest) {
cout << first << ", ";
print(rest...); // recursive call using pack expansion syntax
}

int main()
{
print(); // calls first overload, outputting only a newline
print(1); // calls second overload

// these call the third overload, the variadic template,
// which uses recursion as needed.
print(10, 20);
print(100, 200, 300);
print("first", 2, "third", 3.14159);
}

Output

1
10, 20
100, 200, 300
first, 2, third, 3.14159


注意
Most implementations that incorporate(包含) variadic template functions use recursion of some form(使用某种形式的递归), but it's slightly different from traditional recursion. Traditional recursion involves a function calling itself by using the same signature. (It may be overloaded or templated, but the same signature is chosen each time.)
Variadic recursion involves calling a variadic function template by using differing (almost always decreasing) numbers of arguments, and thereby stamping out a different signature every time.A "base case" is still required, but the nature of the recursion is different.
Variaidic 递归在每次调用的variadic函数模板时使用一个变化参数(几乎总是减少的)参数,并且每次使用的函数签名都不同。
虽然一个基本的例子仍然需要,但是这种递归的本质是不同的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息