2

I want to create a C++ Template for a function, that allows per default intinity arguments of any datatypes. I found some examples where they try to Code the printf function but it doesn't work (they included stdarg.h, i want something like that:)

    //util.cpp
    #include <iostream>
    template<typename ...Args>
    void debugPrint(Args... args)
    {
        // pseudo: foreach args as a:
        std::cout << a;
        // pseudo: endforeach
        std::cout << std::endl;
    }

    //util.hpp
    template<typename ...Args> //?
    void debugPrint(Args...);

    //app.cpp
    #include "util.hpp"
    int main()
    {
        debugPrint("Hallo", " ", "Welt", 1, 2, "\t", 2.3);
        return 0;
    }

Want the consoleoutput: Hallo Welt12 [TAB] 2.3

Then there were an examplte with stdarg.h

    #include <stdarg.h>

    void tprintf(const char* format) // base function
    {
        std::cout << format;
    }

    template<typename T, typename... Targs>
    void tprintf(const char* format, T value, Targs... Fargs) // recursive function
    {
        for (; *format != '\0'; format++) {
            if (*format == '%') {
                std::cout << value;
                tprintf(format + 1, Fargs...); // recursive call
                return;
            }
            std::cout << *format;
        }
    }

So how? :(

Thanks for any answere <3

j0ta
  • 21
  • 3
  • And see also [Why can templates only be implemented in the header file?](https://stackoverflow.com/q/495021/1362568) – Mike Kinghan Mar 04 '19 at 14:16

2 Answers2

4

As with any recursive solution, you need a base case to terminate the recursion. In this situation the base case is when there are no arguments left to print, in which case you do nothing:

void debugPrint() { }

Then the recursive template function, which processes a single "first" argument and then recurses on the remaining variadic arguments:

template <typename FirstArg, typename ...Args>
void debugPrint(FirstArg arg, Args... args)
{
    std::cout << arg;
    debugPrint(args...);
}

Tying it all together:

#include <iostream>

void debugPrint() { }

template <typename FirstArg, typename ...Args>
void debugPrint(FirstArg arg, Args... args)
{
    std::cout << arg;
    debugPrint(args...);
}

int main()
{
    debugPrint("Hallo", " ", "Welt", 1, 2, "\t", 2.3);
}

Outputs:

Hallo Welt12    2.3
TypeIA
  • 16,916
  • 1
  • 38
  • 52
  • 1
    Nice answer! Just adding my two cents: traditionally, the first element is called the _head_ and the rest is the _tail_ :) `template` – YSC Mar 04 '19 at 14:12
  • Thanks! It works, but when I try to give it a Namespace and outsource the Code in a util.h and util.cpp I got also an error :/ – j0ta Mar 04 '19 at 14:20
  • 1
    @j0ta Note that [templates must (usually) be defined in the header](https://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file), putting it in a `.cpp` isn't likely to work. If that thread doesn't help you, consider posting a new question. – TypeIA Mar 04 '19 at 14:25
2

You can use fold expressions to do that (C++17):

template<typename... Args>
void debugPrint(Args const&... args) {
    (std::cout << ... << args);
}

It will expand args with a << between expanded expressions. There is no need for recursion.

Here's a live example.

Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141