0

I'm trying to make a print function in C++ that takes in variable numbers of arguments and prints them each on their own line, like:

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; }

However, if Ty happens to be a std::vector<std::string>, I want to treat it differently (because I want to print every element of the vector on its own line). I looked into partial specialization, but there doesn't seem to be much that I could find on doing so with parameter packs. Here's what I tried:

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; }

However, I'm getting an MSVC error C2768: "'println': illegal use of explicit template arguments". Any suggestions or solutions would be warmly welcomed! For reference, I'm using Visual Studio 2019 Preview and its corresponding compiler version.

Drake Johnson
  • 640
  • 3
  • 19

3 Answers3

4

A simpler way would be to have a print function and overload that:

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; }
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
1

You can do it like this:

/* 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;
 }
Sergey Strukov
  • 373
  • 3
  • 9
0

You can't partially specialize a function template, but you can overload it. Create a new overload of println that takes a std::vector<std::string> as the first argument and a general pack as the rest. Then do the special handling for the vector arg and forward the rest as before. Now your vectors will always be caught by the overload.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155