尖括号中的非类型名称参数与圆括号中的非类型名称参数

Pos*_*elf 5 c++ templates arguments c++11

// Called with doSomething<5>();
template<unsigned i_>
void doSomething()
{
    std::cout << i_ << '\n';
}

// Called with doSomething(5);
void doSomething(unsigned i_)
{
    std::cout << i_ << '\n';
}
Run Code Online (Sandbox Code Playgroud)

什么时候首选第一个选项?为什么它甚至可用?我知道它对于尖括号中的参数与对象本身(而不是特定的构造函数)相关的类很有用,但是它对函数有用吗?

Adr*_*ski 4

这取决于你想如何称呼它。如果您使用该template版本,则i_必须在编译时知道。它在其他示例中更有用,例如您想执行一些在编译时需要信息的其他操作。此外,它的每一个不同的用途都会创造一个新的功能。

template<unsigned i_>
void doSomething() {
    static int a = 0;
    std::cout << a++ << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

对于输入:

doSomething<1>();
doSomething<1>();
doSomething<1>();
doSomething<2>();
Run Code Online (Sandbox Code Playgroud)

输出是:

0
1
2
0
Run Code Online (Sandbox Code Playgroud)

好像还有另外一个功能。一个有用的示例是将编译时已知大小的二维数组传递到函数中。

template<unsigned n>
void doSomething(int (*array)[n]) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

另一方面,第二个函数对相同的函数进行操作,并且不必在编译时提供信息。所以基本上代码是:

void doSomething(unsigned i_) {
    static int a = 0;
    std::cout << i_ << " " << a++ << '\n';
}
Run Code Online (Sandbox Code Playgroud)

用作:

doSomething(1);
doSomething(1);
doSomething(1);
doSomething(2);
Run Code Online (Sandbox Code Playgroud)

给出输出:

1 0
1 1
1 2
2 3
Run Code Online (Sandbox Code Playgroud)

数组示例如下:

void doSomething(int (*array)[5]) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

这限制了你只能使用 nx5 矩阵(其中 n 是一个特定的数字),并且对于每个维度,你都必须手动重载该函数。模板为您提供了一种优雅的方式让编译器为您做这件事。

总而言之 - 第一种方法每次给出一组不同的参数时都会创建一个新函数,并且必须在编译时知道它们,而第二种方法仅创建一个函数并对其进行操作。

  • *数组参数* 必须写为 `int (&amp;array)[m][n]` 才能工作,因为数组**不能**在 C++ 中按值传递。正如克里斯在第一条评论中所解释的那样,您所写的内容将会腐烂。 (2认同)