Print spaces between each element using a fold expression - c++

I am using a fold expression to print elements in a variadic pack, but how do I get a space in between each element?
Currently the output is "1 234", the desired output is "1 2 3 4"
template<typename T, typename Comp = std::less<T> >
struct Facility
{
template<T ... list>
struct List
{
static void print()
{
}
};
template<T head,T ... list>
struct List<head,list...>
{
static void print()
{
std::cout<<"\""<<head<<" ";
(std::cout<<...<<list);
}
};
};
template<int ... intlist>
using IntList = typename Facility<int>::List<intlist...>;
int main()
{
using List1 = IntList<1,2,3,4>;
List1::print();
}

If you need space only between numbers (and not after the last or before the first too), you might do:
template <std::size_t... Is>
void print_seq(std::index_sequence<Is...>)
{
const char* sep = "";
(((std::cout << sep << Is), sep = " "), ...);
}
Demo
(It is similar to my "runtime version") for regular containers with for-loop.

you can that
#include <iostream>
template<typename T>
struct Facility
{
template<T head,T ... list>
struct List
{
static void print()
{
std::cout<<"\"" << head;
((std::cout << " " << list), ...);
std::cout<<"\"";
}
};
};
template<int ... intlist>
using IntList = typename Facility<int>::List<intlist...>;
int main()
{
using List1 = IntList<1,2,3,4>;
List1::print();
}
the fold expression ((std::cout << " " << list), ...) will expands to ((std::cout << " " << list1), (std::cout << " " << list2), (std::cout << " " << list3)...)

In general, you use recursion for tasks like this.
You have to define what happens when there are 2 or more and 1 elements in the list and recursively fall back to those definitions:
template <int ...> struct List;
template <int First, int Second, int ... More> struct List {
static void print() {
std::cout << First << " ";
List<Second, More ...>::print();
}
};
template <int Last> struct List {
static void print() {
std::cout << Last;
}
};

You can reuse print() to achieve this behaviour. Afterall you are doing a fold operation which is by definition resursive.
Live Demo
template<T head,T ... rest_of_pack>
struct List<head , rest_of_pack...>
{
static void print_()
{
std::cout<<head<<" ";
List<rest_of_pack...>::print();
}
};
If you want to process many elements this way you might run into problems with template depth (gcc for instance has a limit of 900). Lucky for you you can use the -ftemplate-depth= option to tweak this behaviour.
You can compile with -ftemplate-depth=100000 and make it work. Note that compilation time will skyrocket (most likely) or in thhe worst case you run out of memory.

Not perfectly aligned with the question but I think may be useful putting here a solution based on fold expressions that generates a string from string-like arguments that should minimize dynamic memory allocations:
#include <iostream>
#include <concepts> // std::convertible_to
#include <string>
#include <string_view>
using namespace std::literals;
template<std::convertible_to<std::string_view>... Args>
[[nodiscard]] std::string mystrconcat(Args&&... args)
{
std::string s;
const std::size_t totsiz = sizeof...(args) + (std::size(args) + ...);
s.reserve(totsiz);
((s+=args, s+=' '), ...);
if(!s.empty()) s.resize(s.size()-1); // Get rid of the trailing delimiter?
return s;
}
int main()
{
std::cout << '\"' << mystrconcat("aa"s,"bb"sv,"ccc") << '\"' << '\n';
}

Related

Variadic template print implementation with separator

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

Best way to specialize function using enable_if for only some types

I have this code that specializes the print function for two types, and reverts back to the base version for any other types.
My question is, is there a way to write this without having to type out the negative case for all the specialized versions in the enable_if of the base print function?
i.e. is there a way to remove all the !std::is_same and still have an unambiguous print function?
Any versions of C++ welcome, but one that works in c++14 would be helpful.
#include <iostream>
template<typename T, std::enable_if_t<!std::is_same<T, int>::value && !std::is_same<T, double>::value, int> = 42>
void print(T data)
{
std::cout << "base:" << data << std::endl;
}
template<typename T, std::enable_if_t<std::is_same<T, double>::value, int> = 42>
void print(T data)
{
std::cout << "double:" << data << std::endl;
}
template<typename T, std::enable_if_t<std::is_same<T, int>::value, int> = 42>
void print(T data)
{
std::cout << "int:" << data << std::endl;
}
int main()
{
std::string foo("foo");
double bar = 1.2;
int baz = 5;
print(foo);
print(bar);
print(baz);
}
For your use case, you can simply provide overloads for the print function as needed
#include <iostream>
template<typename T>
void print(T data)
{
std::cout << "base:" << data << std::endl;
}
void print(double data)
{
std::cout << "double:" << data << std::endl;
}
void print(int data)
{
std::cout << "int:" << data << std::endl;
}
However, if you have more complicated constraints on T, then you can't specialize print without explicitly providing the negation of the constraints in the "default" case.
If you have access to c++17, you can write this in a single function. The usual if-else logic means that the base case is only triggered if the "specializations" are not. This avoids having to specify the negations.
template<typename T>
void print(T data)
{
if constexpr(std::is_same<T, double>{})
std::cout << "double:" << data << std::endl;
else if constexpr(std::is_same<T, int>{})
std::cout << "int:" << data << std::endl;
else // if not same as int or double
std::cout << "base:" << data << std::endl;
}
One way to avoid complementary conditions is to give an overload priority between overload:
template <std::size_t N> struct priority_overload : priority_overload<N - 1> {};
template <> struct priority_overload<0> {}; // Least priority
and then
template<typename T>
void print(T data, priority_overload<0>) // fallback
{
std::cout << "base:" << data << std::endl;
}
template<typename T, std::enable_if_t<condition1<T>::value, int> = 42>
void print(T data, priority_overload<1>)
{
std::cout << "cond1:" << data << std::endl;
}
template<typename T, std::enable_if_t<condition2<T>::value, int> = 42>
void print(T data, priority_overload<2>)
{
std::cout << "cond2:" << data << std::endl;
}
template<typename T>
void print(T data)
{
print(data, priority_overload<10>{});
// Priority should be greater or equal to the one of possible overloads
}

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.

Variadic template pack expansion argument id

I am trying to make a variadic template function that reads elements in order (with an index). The goal is, for example to call the function read_tuple to read two ints with id 0 and 1 (with read_int(0) and read_int(1)).
Here is the code I get so far:
int data[] = {10,20,30,40};
int int_read(int id)
{
return data[id];
}
template <typename T>
T read(int& index)
{
index--;
int value = int_read(index);
std::cout << "index :" << index << " value: " << value << std::endl;
return value;
}
template <typename... Args>
std::tuple<Args...> read_tuple()
{
int index = sizeof...(Args);
return std::tuple<Args...>(read<Args>(index)...);
}
I can call it like that:
auto tuple = read_tuple<int, int>();
std::cout << "First: " << std::get<0>(tuple) << std::endl;
And I get the following output:
index :1 value: 20
index :0 value: 10
First: 10
However, this code is dependent of the order of evaluation of the read function. How can I generate an index dependent of the pack expansion (to avoid undefined behavior)?
As Piotr pointed out, the order of evaluation is garanteed if you use braced-init-list. Be carefull though if you use GCC prior to 4.9.1 as it does not work (c.f. Evaluation order (sequenced-before relation) among initializer-clauses in braced-init-list).
If you use a version that does not garantee the order of initialization (or just want to generate ids) you can use an indexer (from other stackoverflow post):
template<int... I> struct index {
template<int n> using append = index<I..., n>;
};
template<int N> struct make_index {
typedef typename make_index<N - 1>::type::template append<N - 1> type;
};
template<> struct make_index<0> { typedef index<> type; };
template<int N> using indexer = typename make_index<N>::type;
You can use it like that:
int data[] = {10,20,30,40};
int int_read(int id)
{
return data[id];
}
template <typename T>
T read(int index)
{
int value = int_read(index);
std::cout << "index :" << index << " value: " << value << std::endl;
return value;
}
template <typename... Args, int... i>
std::tuple<Args...> read_tuple_indexed(index<i...>)
{
return std::tuple<Args...>(read<Args>(i)...);
}
template <typename... Args>
std::tuple<Args...> read_tuple()
{
return read_tuple_indexed<Args...>(indexer<(sizeof...(Args))>());
}

How to reuse function specialization code?

#include <iostream>
using namespace std;
template<typename T>
void fun(const T & val)
{
cout << " T " << endl;
}
template<>
void fun<int>(const int & val)
{
cout << " specialization same code " << val << endl;
}
template<>
void fun<double>(const double& val)
{
cout << " specialization same code " << val << endl;
}
int main()
{
fun( 1 );
fun( 1.0 );
fun( 'c' );
return 0;
}
Question> Is there a way that I can reuse the function specialization code?
For example, assume both 'int and 'double' specialization has the exactly same implementation code. Is there a method I can prevent the code duplication?
http://codepad.org/awGYWiWv
Thank you
As suggested by #0x499602D2 in the comments, create another function and make sure it gets called only for int or double.
template<typename T>
void bar(const T & val)
{
// Make sure this gets called only for int or double.
static_assert(std::is_same<T, int>::value || std::is_same<T, double>::value);
// Do useful stuff with val.
}
template<>
void fun<int>(const int & val)
{
bar(val);
}
template<>
void fun<double>(const double& val)
{
bar(val);
}
To reuse the same code for multiple types of the same kind, you could use std::enable_if (or boost::enable_if if you are not using C++11) with type traits (a nice example is here).
e.g.:
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
fun(const T& val)
{
cout << " floating point specialisation " << val << endl;
}
(function specialisations of this kind work only in C++11, but you can use a struct or class for the same purpose in older C++ versions)
something like this should give you the level of re-use you want:
#include <iostream>
#include <type_traits>
using namespace std;
// will only compile if T is an arithmetic type
template<typename T,
typename std::enable_if<
std::is_arithmetic<T>::value>::type* = nullptr>
void fun(T val)
{
cout << "the square is " << val * val << endl;
}
int main()
{
int x = 10;
double y = 10;
fun(x);
fun(y);
return 0;
}