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