Variadic模板示例

Adi*_*dib 11 c++ c++11

考虑下面的代码,我不明白为什么必须定义print的空函数.

#include <iostream>
using namespace std;

void print()
{   
}   

    template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args)
{   
    cout << firstArg << endl; // print first argument
    print(args...); // call print() for remaining arguments
}

int main()
{   
    int i=1;
    int  j=2;
    char c = 'T';
    print(i,"hello",j,i,c,"word");

}   
Run Code Online (Sandbox Code Playgroud)

Gam*_*per 13

正确的方式:

变量模板与induction数学概念严格相关.

编译器解析以下函数调用

print('a', 3, 4.0f);
Run Code Online (Sandbox Code Playgroud)

std::cout<< 'a' <<std::endl;
print(3, 4.0f);
Run Code Online (Sandbox Code Playgroud)

这解决了

std::cout<< 'a' <<std::endl;
std::cout<< 3 <<std::endl;
print( 4.0f);
Run Code Online (Sandbox Code Playgroud)

这解决了

std::cout<< 'a' <<std::endl;
std::cout<< 3 <<std::endl;
std::cout<< 4.0f <<std::endl;
print();
Run Code Online (Sandbox Code Playgroud)

此时,它搜索匹配为空函数的函数重载.

  • 具有1个或多个参数的所有函数都与可变参数模板匹配
  • 所有没有参数的函数都与空函数匹配

罪魁祸首是,对于每种可能的参数组合,您必须只有1个功能.


错误1:

执行以下操作将是一个错误

template< typename T>
void print( const T& arg) // first version
{   
    cout<< arg<<endl;
}   

template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args) // second version
{   
    cout << firstArg << endl; // print first argument
    print(args...); // call print() for remaining arguments
}
Run Code Online (Sandbox Code Playgroud)

因为当你调用print编译器时不知道要调用哪个函数.

是否print(3)指的是"第一"或"第二"的版本?两者都是有效的,因为第一个有1个参数,第二个也可以接受一个参数.

print(3); // error, ambiguous, which one you want to call, the 1st or the 2nd?
Run Code Online (Sandbox Code Playgroud)

错误2:

无论如何,以下将是一个错误

// No empty function

template <typename T, typename... Types>
void print (const T& firstArg, const Types&... args) 
{   
    cout << firstArg << endl; // print first argument
    print(args...); // call print() for remaining arguments
}
Run Code Online (Sandbox Code Playgroud)

实际上,如果单独使用它而没有编译器就可以

 print('k', 0, 6.5);
Run Code Online (Sandbox Code Playgroud)

这解决了

 std::cout<<'k'<<std::endl;
 print(0, 6.5);
Run Code Online (Sandbox Code Playgroud)

这解决了

 std::cout<<'k'<<std::endl;
 std::cout<< 0 <<std::endl;
 print( 6.5);
Run Code Online (Sandbox Code Playgroud)

这解决了

 std::cout<<'k'<<std::endl;
 std::cout<< 0 <<std::endl;
 std::cout<< 6.5 <<std::endl;
 print(); //Oops error, no function 'print' to call with no arguments
Run Code Online (Sandbox Code Playgroud)

正如您在上次尝试中看到的那样,编译器尝试print()不带参数进行调用.但是,如果这样的函数不存在则不会被调用,这就是为什么你应该提供那个空函数(不用担心,编译器会优化代码,所以空函数不会降低性能).

  • 你的"错误1"实际上是完全正常的.部分排序正确处理该案例. (2认同)

Gar*_*365 10

如果您没有空print功能,请设想一个带有2个参数的呼叫:

  1. print(a,b)=> cout << a << endl和call print(b)
  2. print(b)=> cout << b << endl和call print()

oups,print()不存在,因为只print存在至少一个参数!所以你需要一个print没有参数.

print 没有任何参数是你最后的电话


Fer*_*eak 6

因为(使用非常"简单"的解释),可变参数模板机制的工作方式类似于递归(它不是递归,但这是理解它的最简单方法),它"消耗"可变参数列表,因此您将不得不定义一个" 停止 "函数,当"消耗"参数列表为" " 时,它将在递归的最后一步重复出现.这是我发现最容易理解这个相当复杂的概念的解释.

在第一步(in main),您将获得一个具有以下参数的函数:(int, const char*, int, int, char, const char*)

然后在可变参数函数本身中慢慢处理可变参数,让你在第二步中(const char*, int, int, char, const char*)依次(int, int, char, const char*)等等......直到你到达最后一个元素(const char*),当你在下一步中处理它时,你最终会得到(),并且编译器需要此函数作为"终止符"

(是的,这是非技术性的,听起来像爷爷青蛙向小青蛙讲故事......)