I wanna implement a Print function which works this:
Print<1, 3>("Hello", "World");
and I hope that it will print "Hello" one time and "World" 3 times.I wonder how to implement it.
Below is my stupid code, of course it failed when compiling:
template <unsigned int n, unsigned int ...n_next,
typename T, typename ...Ts>
void Print(T & t, Ts & ... ts)
{
for(int i = 0; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
Print<n_next..., ts...>(ts...);
}
template <unsigned int n, typename T>
void Print(T & t)
{
for(int i = 0; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
}
This will make it:
template <unsigned int n, typename T>
void Print(T&& t)
{
for(int i = 0; i < n; i++)
{
std::cout << std::forward<T>(t) << " ";
}
std::cout << std::endl;
}
template <std::size_t Idx1, std::size_t... Idx, class T, class... Ts>
void Print(T&& t, Ts&& ... ts) {
Print<Idx1>(std::forward<T>(t));
using expand = int[];
(void)expand{(Print<Idx>(std::forward<Ts>(ts)), 0) ...};
}
I also propose a completely different solution that avoid at all recursion and for() loops.
It simulate template folding in C++14 in initialization of an unused C-style array.
First the main Print(), that expand the variadic lists calling a Print_h() helper function, passing to it the values and list (index sequence) correspinding to numbers of iteration for every value
template <std::size_t ... Ns, typename ... Ts>
void Print (Ts ... ts)
{
using unused=int[];
(void)unused { 0, (Print_h(std::make_index_sequence<Ns>{}, ts), 0)... };
}
Next the helper function that uses the same trick for multiple printing
template <std::size_t ... Is, typename T>
void Print_h (std::index_sequence<Is...>, T const & t)
{
using unused=std::size_t[];
(void)unused { 0, (std::cout << t << " ", Is)... };
std::cout << std::endl;
}
The following is the full compiling C++14 example
#include <utility>
#include <iostream>
template <std::size_t ... Is, typename T>
void Print_h (std::index_sequence<Is...>, T const & t)
{
using unused=std::size_t[];
(void)unused { 0, (std::cout << t << " ", Is)... };
std::cout << std::endl;
}
template <std::size_t ... Ns, typename ... Ts>
void Print (Ts ... ts)
{
using unused=int[];
(void)unused { 0, (Print_h(std::make_index_sequence<Ns>{}, ts), 0)... };
}
int main ()
{
Print<1u, 3u>("hello", "world");
}
If you can't use C++14 but only C++11, isn't difficult to develop substitutes for std::make_index_sequence and std::index_sequence (both available only from C++14).
Obviously in C++17 you can use template folding simplifying the functions as follows
template <std::size_t ... Is, typename T>
void Print_h (std::index_sequence<Is...>, T const & t)
{
((std::cout << t << " ", (void)Is), ...);
std::cout << std::endl;
}
template <std::size_t ... Ns, typename ... Ts>
void Print (Ts ... ts)
{ (Print_h(std::make_index_sequence<Ns>{}, ts), ...); }
I see four problems in your code
(1) the recursive call
Print<n_next..., ts...>(ts...);
is wrong because you have to use Ts... types in template argument list, not ts... values
Print<n_next..., Ts...>(ts...);
or, better (because permit a trick I explain next) without explicating the types
Print<n_next...>(ts...);
(2) is better if you receive as const references the values
template <unsigned int n, unsigned int ...n_next,
typename T, typename ...Ts>
void Print(T const & t, Ts ... ts)
// ..........^^^^^
otherwise you can't call Print() with constant values as follows
Print<1u, 3u>(1, "world");
(3) better use unsigned value for indexes in for loops because you have to test they with unsigned values (minor problem)
// ..VVVVVVVV
for (unsigned int i = 0; i < n; i++)
(4) you have to place the ground case for Print() (the one that receive only a value) before the recursive case.
I suggest to substitute they with
template <typename = void>
void Print ()
{ }
because, this way, all prints are done in recursive version an you don't need to repeat equal code in two different function (but you have to call Print<n_next...>(ts...); the recursion.
So I propose to modify your code as follows
#include <iostream>
template <typename = void>
void Print ()
{ }
template <unsigned int n, unsigned int ...n_next,
typename T, typename ...Ts>
void Print(T const & t, Ts ... ts)
{
for(auto i = 0u; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
Print<n_next...>(ts...);
}
int main ()
{
Print<1u, 3u>("hello", "world");
}
You can make your code work by just swapping the declarations of the two overloads and removing the ts... template argument in the recursive call:
template <unsigned int n, typename T>
void Print(T & t)
{
for(unsigned int i = 0; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
}
template <unsigned int n, unsigned int ...n_next,
typename T, typename ...Ts>
void Print(T & t, Ts & ... ts)
{
for(unsigned int i = 0; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
Print<n_next...>(ts...);
}
(also, be consistant with signedness)
Demo
Furthermore, you don't need to duplicate the printing part, just call the other overload:
template <unsigned int n, typename T>
void Print(T & t)
{
for(unsigned int i = 0; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
}
template <unsigned int n, unsigned int ...n_next,
typename T, typename ...Ts>
void Print(T & t, Ts & ... ts)
{
Print<n>(t);
Print<n_next...>(ts...);
}
Alternatively, if you can use C++17 for fold expressions, you can do the following (use forwarding references and std::forward if you need to):
template<typename T>
void Print(unsigned int n, T& t)
{
for(unsigned int i = 0; i < n; i++)
{
std::cout << t << " ";
}
std::cout << std::endl;
}
template<unsigned int... Ns, typename... Ts>
void Print(Ts&... ts)
{
(Print(Ns, ts), ...);
}
Demo
Related
The following code compiles and runs on MSVC 2019 and Clang trunk. (I think it needs at least C++17). It does not run on gcc-trunk and I believe the consensus is that this is due to a bug in gcc.
However, when any of the elements are replaced by a user type or a pointer type, it fails on all compilers. To see this, uncomment the tuple_c definition near the end.
I'm actually slightly surprised this works at all since it appears to be specializing a function with a universal-ref parameter with one that has an r-value-ref parameter. Maybe that's ok? If it is, why is it failing with the struct?
Is there a better way of writing this? I mean in general. I'm well aware of std::tuple.
#include <iostream>
using namespace std;
template <typename... TP> class Tuple
{
};
template <> class Tuple <>
{
};
template <typename Head, typename... Tail> class Tuple <Head, Tail...>
{
Head head;
Tuple <Tail...> tail;
public:
Tuple ()
{
}
Tuple (const Head& head_in, const Tail&...tail_in)
: head (head_in), tail (tail_in...)
{
}
template <int i> auto Get ()
{
return tail.template Get <i-1> ();
}
template <> auto Get <0> ()
{
return head;
}
template <int i, typename T> void Set (T&& v) // T&& is a universal ref
{
tail.template Set <i-1, T> (static_cast <T&&> (v));
}
template <int i, typename T> void Set (const T& v)
{
tail.template Set <i-1, T> (v);
}
template <> void Set <0, Head> (Head&& v) // Head&& is an rv-ref
{
head = v;
}
template <> void Set <0, Head> (const Head& v)
{
head = v;
}
};
template <typename Head, typename... Tail> Tuple <Head, Tail...> MakeTuple (Head&& head, Tail&&...tail)
{
Tuple <Head, Tail...> result (head, tail...);
return result;
}
struct S
{
int x;
int y;
};
ostream& operator << (ostream& out, const S& s)
{
out << "{" << s.x << "," << s.y << "}";
return out;
}
int main(int argc, char* argv[])
{
auto tuple_a = MakeTuple (1,2,3,4);
tuple_a.Set <1,int> (42);
cout << tuple_a.Get <0> () << '\n';
cout << tuple_a.Get <1> () << '\n';
cout << tuple_a.Get <2> () << '\n';
cout << tuple_a.Get <3> () << '\n';
auto tuple_b = MakeTuple (1,2.3f,3,4);
tuple_b.Set <1,float> (42.3f);
cout << tuple_b.Get <0> () << '\n';
cout << tuple_b.Get <1> () << '\n';
cout << tuple_b.Get <2> () << '\n';
cout << tuple_b.Get <3> () << '\n';
S s {4,5};
//auto tuple_c = MakeTuple (1,2.3f,3,s);
return 0;
}
First, before CWG 727 you're not allowed to specialize a member function template inside a class scope. You will have to use constexpr-if, tag-dispatching or SFINAE to handle the i==0 case.
In c++14 using std::enable_if_t that would be:
template <int i, typename T>
std::enable_if_t<i != 0> Set(T&& v)
{
tail.template Set<i-1>(static_cast<T&&>(v));
}
template <int i, typename T>
std::enable_if_t<i == 0> Set(T&& v)
{
head = static_cast<T&&>(v);
}
In c++17 using constexpr-if it becomes:
template <int i, typename T>
void Set(T&& v)
{
if constexpr (i == 0) head = static_cast<T&&>(v);
else tail.template Set<i-1>(static_cast<T&&>(v));
}
Secondly, once compilers allow you to specialize a function template inside a class cope, there is another problem with your current approach. Your MakeTuple implementation, due to how template argument deduction works for forwarding references, creates a tuple of reference types corresponding to those MakeTuple arguments that are lvalues:
template <typename Head, typename... Tail>
Tuple<Head, Tail...> MakeTuple(Head&& head, Tail&&... tail);
This makes your comment/assumption:
void Set<0, Head>(Head&& v) // Head&& is an rv-ref
invalid.
That is, for an lvalue expression s:
S s{ 4, 5 };
MakeTuple(s);
The deduced Head is S& (it's also the type of head after reference collapsing). Then the compiler attempts to instantiate Tuple<S&> and it generates the following two declarations:
void Set<0, S&>(S& && v);
void Set<0, S&>(S& const& v);
After reference collapsing it ends up with:
void Set<0, S&>(S& v);
void Set<0, S&>(S& v);
At this point, not only both definitions are the same, but also the compiler can't decide which of the primary function templates:
template <int i, typename T>
void Set(T&& v);
template <int i, typename T>
void Set(const T& v);
they are specializations of, as using T=S& matches both. This could be solved by decaying each type before storing it in a tuple:
template <typename Head, typename... Tail>
Tuple<std::decay_t<Head>, std::decay_t<Tail>...> MakeTuple(Head&& head, Tail&&... tail);
My question was answered above but I thought it might be useful to include the complete code for the solution. It now works for all types except arrays and string literals.
#include <iostream>
using namespace std;
template <typename... TP> class Tuple
{
};
template <> class Tuple <>
{
};
template <typename Head, typename... Tail> class Tuple <Head, Tail...>
{
Head head;
Tuple <Tail...> tail;
public:
Tuple ()
{
}
Tuple (const Head& head_in, const Tail&...tail_in)
: head (head_in), tail (tail_in...)
{
}
template <int i> auto Get ()
{
return tail.template Get <i-1> ();
}
template <> auto Get <0> ()
{
return head;
}
template <int i, typename T> void Set (T&& v)
{
tail.template Set <i-1, T> (static_cast <T&&> (v));
}
template <int i, typename T> void Set (const T& v)
{
tail.template Set <i-1, typename std::decay<T>::type> (v);
}
template <> void Set <0, typename std::decay<Head>::type> (Head&& v)
{
head = v;
}
template <> void Set <0, typename std::decay<Head>::type> (const Head& v)
{
head = v;
}
};
template <typename Head, typename...Tail> Tuple <typename std::decay <Head>::type, typename std::decay<Tail>::type...> MakeTuple (Head&& head, Tail&&...tail)
{
Tuple <typename std::decay <Head>::type, typename std::decay<Tail>::type...> result (head, tail...);
return result;
}
struct S
{
int x;
int y;
};
ostream& operator << (ostream& out, const S& s)
{
out << "{" << s.x << "," << s.y << "}";
return out;
}
int main(int argc, char* argv[])
{
const char* p = "hello";
S s;
int v = 32;
auto tuple_a = MakeTuple (1.0,v,p,s);
cout << tuple_a.Get <0> () << endl;
cout << tuple_a.Get <1> () << endl;
cout << tuple_a.Get <2> () << endl;
cout << tuple_a.Get <3> () << endl;
S s_update {10,12};
tuple_a.Set <3> (s_update);
const char* p_update = "goodbye";
tuple_a.Set <2> (p_update);
cout << tuple_a.Get <0> () << endl;
cout << tuple_a.Get <1> () << endl;
cout << tuple_a.Get <2> () << endl;
cout << tuple_a.Get <3> () << endl;
}
Most samples of c++ books leverage recursively mechanism to print std::tuple.
Is it possible to print std::tuples iteratively by leverage sizeof...(Typename)?
For example, the function signature is like below:
template<typename... Ts>
constexpr void PrintTuple(std::tuple<Ts...>& tuple)
Then I could use sizeof...(Ts) to know how many elements in the tuple and then
I could use std::get< i >(tuple) to retrieve the individual element?
Here's one of the possible solutions:
#include <cstddef>
#include <iostream>
#include <tuple>
#include <type_traits>
#include <utility>
template <typename T, std::size_t ...I, typename F>
void tuple_foreach_impl(T &&tuple, std::index_sequence<I...>, F &&func)
{
// In C++17 we would use a fold expression here, but in C++14 we have to resort to this.
using dummy_array = int[];
dummy_array{(void(func(std::get<I>(tuple))), 0)..., 0};
}
template <typename T, typename F> void tuple_foreach(T &&tuple, F &&func)
{
constexpr int size = std::tuple_size<std::remove_reference_t<T>>::value;
tuple_foreach_impl(std::forward<T>(tuple), std::make_index_sequence<size>{},
std::forward<F>(func));
}
int main()
{
auto x = std::make_tuple("Meow", 1, 2.3);
tuple_foreach(x, [](auto &&value)
{
std::cout << value << ' ';
});
// Prints:
// Meow
// 1
// 2.3
}
With tuple_foreach making a proper printer should be simple.
template <typename T> void print_tuple(const T &tuple)
{
std::cout << '{';
tuple_foreach(tuple, [first = true](auto &value) mutable
{
if (!first)
std::cout << "; ";
else
first = 0;
std::cout << value;
});
std::cout << '}';
}
// ...
print_tuple(std::make_tuple("Meow", 1, 2.3)); // Prints `{Meow; 1; 2.3}`
c++20 makes everything very easy:
void print_tuple(auto&& t) noexcept
{
[&]<auto ...I>(std::index_sequence<I...>) noexcept
{
(
[&]() noexcept
{
if constexpr(I)
{
std::cout << ", ";
}
std::cout << std::get<I>(t);
}(),
...
);
std::cout << '\n';
}
(
std::make_index_sequence<
std::tuple_size_v<std::remove_cvref_t<decltype(t)>>
>()
);
}
I have the following pseudo code:
template <typename... Ts>
void f(int index) {
std::vector<std::function<void(void)>> funcs;
funcs.push_back([](){ std::cout << typeid(type_1).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_2).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_3).name() << std::endl; });
funcs.push_back([](){ std::cout << typeid(type_4).name() << std::endl; });
funcs[index]();
}
Imagine that the Ts... parameter pack holds type_1, type_2, type_3 and type_4.
how can I expand the parameter pack in order to achieve something like this? I mean - how can I get 4 push_back() calls if there are 4 parameters in the template pack, and also have the different types in the different lambdas? I don't know the syntax..
And can I actually get some sort of an array of such functions at compile time, so there are no push_backs at runtime?
C++17 solution is ok, but C++14 is best.
For C++17, something like this, I suppose
(funcs.push_back([](){ std::cout << typeid(Ts).name() << std::endl; }), ...);
or, better (IMHO), using emplace_back()
(funcs.emplace_back([](){ std::cout << typeid(Ts).name() << std::endl; }), ...);
But remeber that is
std::vector<std::function<void(void)>>
not
std::vector<std::function<void>>
In C++14 (and C++11) you can obtain something similar with the trick of intialization of the unused array; the function can be written as
template <typename ... Ts>
void f (int index)
{
using unused = int[];
std::vector<std::function<void(void)>> funcs;
(void)unused { 0, (funcs.emplace_back([]()
{ std::cout << typeid(Ts).name() << std::endl; }), 0)... };
funcs[index]();
}
Update.
From re-reading the question I think you just want to call the function once for the I'th type.
I which case it's trivial at compile time:
#include <array>
#include <type_traits>
#include <iostream>
#include <string>
template <class T>
void show_type()
{
std::cout << typeid(T).name() << std::endl;
}
template <typename... Ts>
void f(int index) {
using function_type = void(*)();
constexpr auto size = sizeof...(Ts);
constexpr std::array<function_type, size> funcs =
{
&show_type<Ts>...
};
funcs[index]();
}
int main()
{
for(int i = 0 ; i < 3 ; ++i)
f<int, double, std::string>(i);
}
example output:
i
d
NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
Something along these lines, perhaps:
template <typename... Ts>
void f(int index) {
int i = 0;
auto _ = {
(index == i++ ? ((std::cout << typeid(Ts).name() << std::endl) , 0) : 0) ...
};
}
Demo
If all you want to do is do something for the nth type in a template parameter pack, where n is a runtime variable, then the vector + function approach isn't really great. Better to add an index sequence in there and fold:
template <typename T> struct tag_t { using type = T; };
template <typename T> constexpr inline tag_t<T> tag{};
template <class F, size_t... Is, typename... Tags>
void match(F f, size_t i, std::index_sequence<Is...>, Tags... tags) {
auto inner = [&](auto tag) { f(tag); return true; };
bool matched = ((i == Is && inner(tags)) || ...);
if (!matched) {
// failure case?
}
}
template <typename... Ts, class F>
void match(F f, size_t i) {
return match(f, i, std::index_sequence_for<Ts...>(), tag<Ts>... );
}
template <typename... Ts>
void foo(int index) {
match<Ts...>([](auto tag){
std::cout << typeid(typename decltype(tag)::type).name() << std::endl;
}, index);
}
This construction allows you to add a failure case, where you might call the passed-in function with some special type:
struct failure { };
template <class F, size_t... Is, typename... Tags>
void match(F f, size_t i, std::index_sequence<Is...>, Tags... tags) {
auto inner = [&](auto tag) { f(tag); return true; };
bool matched = ((i == Is && inner(tags)) || ...);
if (!matched) {
f(failure{});
}
}
template <typename... Ts>
void foo(int index) {
match<Ts...>(overload(
[](auto tag){
std::cout << typeid(typename decltype(tag)::type).name() << std::endl;
},
[](failure ) { /* ... */ }
), index);
}
I have a syntax problem with expanding a tuple to its content.
The working code I have:
class Example
{
public:
static void Go( int i, float f)
{
std::cout << "p1: " << i << std::endl;
std::cout << "p2: " << f << std::endl;
}
template <typename T, size_t ... I>
static void Do( T parm )
{
Go( std::get<I>( parm)...);
}
};
int main()
{
using X = std::tuple<int, float>;
Example::Do<X,0,1>( std::make_tuple( 1,2.2)) ;
}
But I want to call the expansion with something like
int main()
{
using X = std::tuple<int, float>;
using IDX = std::std::index_sequence_for<int, float>;
Example::Do<X,IDX>( std::make_tuple( 1,2.2)) ;
}
So I am searching for something like ( which can not compiled... ):
template <typename T, size_t ... I>
static void Do<T, std::index_sequence<I...>>(T parm)
{
Go( std::get<I>( parm)...);
}
Pass the index sequence by value:
template <typename T, size_t... I>
static void Do(T parm, std::index_sequence<I...>)
{
Go(std::get<I>(parm)...);
}
Call the method like this:
Example::Do(std::make_tuple(1, 2.2),
std::index_sequence_for<int, float>{});
The problem is that your std::index_sequence (IDX) is not expanding in the template parameters to what you need:
Example::Do<X, IDX>(std::make_tuple(1, 2.2));
...will not "expand" to:
Example::Do<X, 0, 1>(std::make_tuple(1, 2.2)); // This works
What you need is to let the compiler deduce the template arguments for ...I, to do so change your static method to:
template <typename T, size_t ... I>
static void Do(T parm, std::index_sequence<I...>)
{
Go(std::get<I>(parm)...);
}
And then call it with:
Example::Do(std::make_tuple(1, 2.2), IDX{});
The compiler will automatically deduce the template arguments and call Example::Do<X, 0, 1> as needed.
If you want to be able to call Do without the second arguments, you can add another layer of abstraction in Example:
class Example
{
public:
static void Go(int i, float f) {
std::cout << "p1: " << i << std::endl;
std::cout << "p2: " << f << std::endl;
}
template <typename Tuple>
static void Do(Tuple &&parm) {
_Do(std::forward<Tuple>(parm),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{});
}
private:
template <typename Tuple, size_t... I>
static void _Do(Tuple &&parm, std::index_sequence<I...>) {
Go(std::get<I>(std::forward<Tuple>(parm))...);
}
};
Then:
Example::Do(std::make_tuple(1, 2.2));
Note that the three versions:
Example::Do<X, 0, 1> (std::make_tuple(1, 2.2));
Example::Do(std::make_tuple(1, 2.2), IDX{});
Example::Do(std::make_tuple(1, 2.2));
Will likely results in the same code after compiler optimization (on my machine with clang++-3.7 and -O1, the three assembly files are strictly identical).
I want to write a function print which behaves differently according to the type of its argument.
Here is my implementation:
template <typename T, typename std::enable_if<std::is_array<T>::value, int>::type = 0>
void print(const T &v) {
std::cout << "array: ";
for (const auto &e : v) {
std::cout << e << ", ";
}
std::cout << std::endl;
}
template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void print(const T &v) {
std::cout << "integral: " << v << std::endl;
}
template <typename T, typename std::enable_if<!(std::is_array<T>::value || std::is_integral<T>::value), int>::type = 0>
void print(const T &v) {
std::cout << "default: " << v << std::endl;
}
This code works as expected, but the conditions in the last specification are too complicated.
Is there any solution to simplify the last one?
A general approach you can use for a default case is to have a function which takes a variable argument list. This will only be used if no other function matches. Here is an example:
template <typename T, typename std::enable_if<std::is_array<T>::value, int>::type = 0>
void print_helper(const T &v,int) {
std::cout << "array: ";
for (const auto &e : v) {
std::cout << e << ", ";
}
std::cout << std::endl;
}
template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void print_helper(const T &v,int) {
std::cout << "integral: " << v << std::endl;
}
template <typename T>
void print_helper(const T &v,...) {
std::cout << "default: " << v << std::endl;
}
template <typename T>
void print(const T &v)
{
print_helper(v,0);
}
For only two overloads, the extra function may not be worth it, but as you get more overloads this form can really pay off for the default case.
We can use an extra chooser to make things better for us, courtesy of Xeo:
struct otherwise{ otherwise(...){} };
template<unsigned I>
struct choice : choice<I+1>{};
// terminate recursive inheritence at a convenient point,
// large enough to cover all cases
template<> struct choice<10>{};
Then each ranking on our choice list will be preferred to the next, and we just have to disable as we go:
// just forward to our first choice
template <class T> void print(const T &v) { print(v, choice<0>{}); }
Where our top choice is array:
template <class T, class = std::enable_if_t<std::is_array<T>::value>>
void print(const T& v, choice<0> ) { ... }
And then integral:
template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void print(const T& v, choice<1> ) { ... }
And then anything
template <class T>
void print(const T& v, otherwise ) { ... }
This structure allows for arbitrarily many choices.