Search code examples
c++templatesvariadic-functionsgeneric-programmingpartial-specialization

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


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.


Solution

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