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
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
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
}
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.
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))>());
}
#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;
}