Variadic template print implementation with separator - c++

I'm trying to do a simple PoC with variadic templates. Right now, my code is as follows:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
void println(const T& head) {
cout << head << endl;
}
template <typename T, typename ... Args>
void println(const T& head, Args&& ... args) {
cout << head << ", ";
println(args...);
}
int main() {
println(1,2,3,4,5,6);
}
Here, the separator is , , but I would like to be user provided, and also with a default value. However, trying something like void println(const T& head, const Args&... args, const string& sep = ",") is not going to work due the parameter pack. Is there any workaround to do this in a simple manner?

I propose the following, non recursive, version. Based on a template defaulted value separator
#include <iostream>
template <char Sep = ',', typename T, typename ... Args>
void println (T const & head, Args const & ... args)
{ ((std::cout << head), ..., (std::cout << Sep << ' ' << args)) << std::endl; }
int main()
{
println(1,2,3,4,5,6);
println<':'>(1,2,3,4,5,6);
}
that prints
1, 2, 3, 4, 5, 6
1: 2: 3: 4: 5: 6

Related

What is the variadic function template overloading precedence rule?

I'm using variadic function templates in the common recursive format and I need to change the behaviour of the function whenever I'm handling a vector.
If the functions templates were not variadic, overloading works well, but with variadic function templates, the overloading resolution seems to change when unpacking the argument pack.
Below some code to explain better what I mean.
#include <iostream>
#include <vector>
template<typename T>
void complexfun(T x) {
std::cout << "1 end" << std::endl;
}
template<typename T, typename... Args>
void complexfun(T x, Args... args) {
std::cout << "1 ";
complexfun(args...);
}
template<typename T>
void complexfun(std::vector<T> x) {
std::cout << "2 end" << std::endl;
}
template<typename T, typename... Args>
void complexfun(std::vector<T> x, Args... args) {
std::cout << "2 ";
complexfun(args...);
}
int main() {
std::vector<int> vint = {2, 3, 4};
float x1 = 9.4;
complexfun(vint); // output: 2 end -> OK
complexfun(vint, x1); // output: 2 1 end -> OK
complexfun(x1, vint); // output: 1 1 end -> WRONG: need 1 2 end
return 0;
}
In the execution of complexfun(x1, vint) we should have complexfun(vint), but it does not behave as the "standalone" call complexfun(vint).
Any help on why this is the case and how to fix it is greatly appreciated!
You need to declare template<typename T> void complexfun(std::vector<T>) before the function that is supposed to be using it.
Just swap the order of those function templates so you get:
template<typename T> // this function template
void complexfun(std::vector<T>) {
std::cout << "2 end" << std::endl;
}
template<typename T, typename... Args> // ...before this function template
void complexfun(T, Args... args) {
std::cout << "1 ";
complexfun(args...);
}
Demo

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

How do I realise a Template for a recursive function that allows many parameters of undefined datatypes in C++? [duplicate]

This question already has answers here:
How to make a variadic macro for std::cout?
(4 answers)
Closed 3 years ago.
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
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
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.

How to define template function overload to match empty std::tuple<>?

I'd like to distinguish between empty and non-empty tuples, and I came up with the following solution (example):
#include <tuple>
#include <iostream>
template <typename ... Args>
void function(const std::tuple<Args...>& t)
{
std::cout << "empty tuple" << std::endl;
}
template <typename Head, typename ... Args>
void function(const std::tuple<Head, Args...>& t)
{
std::cout << "tuple of size: " << sizeof...(Args) + 1 << std::endl;
}
int main()
{
function(std::make_tuple()); // picks 1st function
function(std::make_tuple(1)); // picks 2nd function
function(std::make_tuple(1, 2, 3, '4')); // picks 2nd function
}
However, using variadic Args to match std::tuple<> is misleading for a reader, and I think that introducing Head in the 2nd overload is excessive. Is there a simple way to write an overload that matches std::tuple<> directly?
Did you try:
void function(const std::tuple<>& t) { ... }
?
Then you don't need to write Head out separately in the second function. Live example: http://coliru.stacked-crooked.com/a/1806c3a8a3e6b2d1.

Output all variadic template parameters

I am simply trying to output all of the parameters passed to a variadic function template. I tried this recursive approach:
#include <iostream>
template<typename TFirst, typename... Arguments>
void Output(TFirst first, Arguments... parameters)
{
std::cout << first << std::endl;
Output(parameters);
}
template<typename TFirst>
void Output(TFirst first)
{
std::cout << first << std::endl;
}
void Output()
{
// do nothing
}
int main()
{
Output(1.0f, 2);
}
but I get parameter packs not expanded with '...'. Can anyone explain what is wrong here?
--------- EDIT ------------
Here is the solution:
#include <iostream>
template<typename T>
inline void showArguments(T&& arg) { std::cout << arg << std::endl; }
template<typename First, typename... Rest>
inline void showArguments(First&& first, Rest&& ...rest)
{
showArguments(first);
showArguments(rest...);
}
int main()
{
showArguments("Hello", "World", 1, 2.3, false, true);
}
Should be
template<typename TFirst, typename... Arguments>
void Output(TFirst first, Arguments... parameters)
{
std::cout << first << std::endl;
Output(parameters...);
}
(note the trailing ... after the parameters)