【问题标题】:Variadic Templates example not compiling可变参数模板示例未编译
【发布时间】:2016-04-08 23:46:35
【问题描述】:

我正在尝试掌握和理解可变参数模板的概念。 我遇到了this 例子

#include <iostream>
using namespace std;

//Output function to output any type without type specifiers like printf() family
template <typename T, typename ...P>
void output(T t, P ...p)
{
  cout << t << ' ';
  if (sizeof...(p)) { output(p...); }
  else { cout << '\n'; }
}

//Since variadic templates are recursive, must have a base case
void output() { cout << "\n"; }

//Test it
int main()
{
  //output();
  output('5', 2);

  return(0);
}

但是当我尝试运行它时,我得到了错误

main.cpp: In instantiation of 'void output(T, P ...) [with T = int; P = {}]':
main.cpp:10:29:   required from 'void output(T, P ...) [with T = char; P = {int}]'
main.cpp:21:16:   required from here
main.cpp:10:29: error: no matching function for call to 'output()'
   if (sizeof...(p)) { output(p...); }
                             ^
main.cpp:7:6: note: candidate: template<class T, class ... P> void output(T, P ...)
 void output(T t, P ...p)
      ^
main.cpp:7:6: note:   template argument deduction/substitution failed:
main.cpp:10:29: note:   candidate expects at least 1 argument, 0 provided
   if (sizeof...(p)) { output(p...); }
                             ^

关于如何修复它的任何建议。谢谢

【问题讨论】:

  • 交换两个output 重载。
  • 那不是运行,那是编译。我真的很想知道可变参数模板如何导致运行时错误。

标签: c++ templates c++11


【解决方案1】:

切换输出函数的声明顺序:

//Since variadic templates are recursive, must have a base case
void output() { cout << "\n"; }

//Output function to output any type without type specifiers like printf() family
template <typename T, typename ...P>
void output(T t, P ...p)
{
  cout << t << ' ';
  if (sizeof...(p)) { output(p...); }
  else { cout << '\n'; }
}

对于模板函数,重载解析规则变得很奇怪,所以编译器只考虑了到目前为止已经声明的重载,而没有考虑你的非模板。在编写多个重载时,其中一个或多个是模板函数,声明顺序很重要。

【讨论】:

  • 你能解释一下发生了什么吗?
【解决方案2】:

它比声明顺序更复杂。看到这个答案:Switch passed type from template

template <typename T, typename ...P>
void output(T t, P ...p)
{
  cout << t << ' ';
  if (sizeof...(p)) { output(p...); } // HERE
  else { cout << '\n'; }
}

无论函数是否被实际调用,它都必须存在。您不能在函数中拥有一个虽然从未执行但会导致语法错误的分支。因此,您对sizeof...(p) 的检查毫无意义。

所以为了让你的代码更清晰,因为它完全表达了自己并且没有额外的东西,改成这样:

void output() { cout << "\n"; }

//Output function to output any type without type specifiers like printf() family
template <typename T, typename ...P>
void output(T t, P ...p)
{
  cout << t << ' ';
  output(p...);
}

您也不必按该顺序定义它们,尽管这样更容易。你可以这样做:

void output();

//Output function to output any type without type specifiers like printf() family
template <typename T, typename ...P>
void output(T t, P ...p)
{
  cout << t << ' ';
  output(p...);
}

void output() { cout << "\n"; }

甚至这个:

template <typename T, typename ...P>
void output(T t, P ...p)
{
  void output();
  cout << t << ' ';
  output(p...);
}

void output() { cout << "\n"; }

编辑:实际上,您可以避免需要 0 参数版本:

template < typename T >
void output(T t) { cout << t << "\n"; }

//Output function to output any type without type specifiers like printf() family
template <typename T, typename ...P>
void output(T t, P ...p)
{
  cout << t << ' ';
  output(p...);
}

【讨论】:

  • 最后一个不行。本地 output 声明隐藏了模板。
【解决方案3】:

T t 将是第一个参数,P ...p 是其余参数。

output('5', 2);
//          ^ 

你把函数void output()放在下面,它不可见

要解决这个问题,您可以声明上面的函数,以便看到它:

void output();

或者将不带参数的函数移到另一个函数之上:

void output() { cout << "\n"; }

template <typename T, typename ...P>
void output(T t, P ...p) { // ... }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-10
    • 2016-09-14
    • 2019-07-27
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多