有没有办法为递归函数部分特化带有参数包的模板?

Is there a way to partially specialize a template with parameter packs for a recursive function?

我正在尝试在 C++ 中创建一个打印函数,它接收可变数量的参数并将它们打印在各自的行中,例如:

template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
    std::cout << cur_line << '\n';
    println(other_lines);
}
void println() { std::cout << std::flush; }

但是,如果 Ty 恰好是 std::vector<std::string>,我想以不同的方式对待它(因为我想在自己的行上打印矢量的每个元素)。我研究了部分专业化,但在使用参数包这样做时,我似乎找不到太多东西。这是我尝试过的:

template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
    std::cout << cur_line << '\n';
    println(other_lines);
}

template<typename... Types>
void println<std::vector<std::string>, Types...>
    (std::vector<std::string> cur_line, Types... other_lines)
{
    for (const auto& line : cur_line)
    {
        std::cout << line << '\n';
    }
    println(other_lines);
}

void println() { std::cout << std::flush; }

但是,我收到 MSVC 错误 C2768:“'println': illegal use of explicit template arguments”。 任何建议或解决方案都将受到热烈欢迎!作为参考,我使用的是 Visual Studio 2019 Preview 及其相应的编译器版本。

一种更简单的方法是使用打印函数并重载:

template < typename T >
void print(const T& line)
{
    std::cout << line << '\n';
}

template < typename T >
void print(const std::vector<T>& line)
{
    for (const auto& element : line)
    {
        print(element);
    }
}

template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
    print(cur_line);
    println(other_lines);
}

void println() { std::cout << std::flush; }

您不能部分特化函数模板,但可以重载它。创建一个 println 的新重载,它将 std::vector<std::string> 作为第一个参数,将通用包作为其余参数。然后对向量 arg 进行特殊处理,并像以前一样转发其余部分。现在你的向量总是会被过载捕获。

你可以这样做:

/* main.cpp */

#include <iostream>
#include <vector>
#include <string>

using namespace std;

template <class T>
void PrintLine(const T &t)
 {
  cout << t << endl ;
 }

template <class T>
void PrintLine(const vector<T> &t)
 {
  for(auto &obj : t ) PrintLine(obj);
 }

template <class ... TT>
void PrintLines(const TT & ... tt)
 {
  ( PrintLine(tt) , ... );
 }

/* main() */

int main()
 {
  vector<string> list{"a","b","c"};

  PrintLines(1,2,3,list);

  return 0;
 }