High level print function for C++

Viewed 226

Is there a way to create a function or a macro in C++ that you can use like Python? What i mean is a function like:

print(i); // i is an integer.
print(i, s); // i is an integer, s is a std::string. They are separated by a white space.

A function that takes in a number of arguments, then just prints them out regardless of the types.

3 Answers

Use streams:

std::cout << i << ' ' << s << '\n';

For more complex formatting consider fmt, it supports the syntax for python's str.format as well as printf style formatting (but typesafe).

If you are allowed to use C++17, you can do it using fold-expression, like this:

#include <iostream>

template<class ...Args>
void print(const Args &...args) {
    auto seq_started = false;
    auto print_impl = [&](auto &value) mutable {
        if (seq_started) {
            std::cout << " " << value;
        } else {
            seq_started = true;
            std::cout << value;
        }
    };
    
    (print_impl(args), ...);
}

int main() {
    print("foo", 10, "bar", 20, "baz");
    return 0;
}

I assume that the question is about general solution and that print is just an example.

The answer is: yes, with a combination of overloads and templates. First you setup functions per type:

void print_impl(const std::string& arg) {
    std::cout << arg;
}

void print_impl(int arg) {
    // Note: this is an example. Of course cout already
    // does that for us with simple
    //   std::cout << arg;
    print_impl(convert_to_string(arg));
}

// cout already has lots of overloads, we can take
// advantage of that if needed:
template<class TArg>
void print_impl(TArg&& arg) {
    std::cout << std::forward<TArg>(arg);
}

then templates:

template<class TArg>
void print(TArg&& arg) {
    print_impl(std::forward<TArg>(arg));
}

template<class TArg1, class ... TArgs>
void print(TArg1&& arg1, TArgs&& ... args) {
    print_impl(std::forward<TArg1>(arg1));   // <-- print first argument
    print_impl(" ");   // <-- insert separator, requires const std::string& overload
    print(std::forward<TArgs>(args)...);   // <-- recursive call
}

In the code above you can replace calls to print_impl with calls to std::cout << operator directly, if needed. Although I would keep print_impl because it is a nice layer above std::cout in case you want to replace it in the future.

Then you can use it similar to Python:

int main()
{
    print("test");
    print(1, 2, "foo");
    print("foo", 1, 2);
    return 0;
}
Related