Variadic C++ Templates Termination After Unpack? - c++

I'm trying to use C++ variadic templates to unpack a list of arguments of variable type, how would I remove the "T" object in the following artificial example:
struct Test
{
template <typename T, typename... Args>
void foo(T t, int i, Args... args) { foo(t, args...); }
template <typename T, typename... Args>
void foo(T t, double d, Args... args) { foo(t, args...); }
template <typename T>
void foo(T t) { }
};
struct DummyObject { };
and then executed like this:
DummyObject dummy;
Test test;
test.foo(dummy, 4, 5.0, 6, 7.0, 8.0, 9);
I'd like to remove the need to pass in the "dummy" object at all, I just can't figure out what the final "foo" function should look like in this case.

Let me flesh out your sample slightly:
struct Test
{
template <typename T, typename... Args>
void foo(T t, int i, Args... args) { doIThing(i); foo(t, args...); }
template <typename T, typename... Args>
void foo(T t, double d, Args... args) { doDThing(d); foo(t, args...); }
template <typename T>
void foo(T t) { }
};
So there's the two functions that do actual work: doIThing and doDThing. You got it 99% right, just... remove T.
struct Test
{
template <typename... Args>
void foo(int i, Args... args) { doIThing(i); foo(args...); }
template <typename... Args>
void foo(double d, Args... args) { doDThing(d); foo(args...); }
void foo() { }
};
Running here: http://coliru.stacked-crooked.com/a/b35ac716cf2960b3

Other method is to remove recursive call and have something like:
struct Test
{
template <typename... Args>
void foos(Args... args)
{
(foo(args), ...); // C++17 fold expression
#if 0 // C++11 or C++14
const int dummy[] = {0, (foo(args), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable
#endif
}
void foo(int t) { /*...*/ }
void foo(double t) { /*...*/ }
template <typename t> void foo(T t) { /**/ }
};
And then use it:
Test test;
test.foos(4, 5.0, 6, 7.0, 8.0, 9);

Related

For each type, call a template function with each of these types

As the title says, I'm trying to create something to be used as followed :
template <typename T>
void testFunc(int& i)
{
...
}
int i { 0 };
ForEach<int, float>::run<testFunc>(i);
I've already tried some things, but I'm hitting some problems:
template<typename CurrentComponentType, typename... ComponentTypes>
struct ForEach
{
template<void (&func)(auto&&... args)>
static constexpr void run(auto&&... args)
{
func<CurrentComponentType>(std::forward<decltype(args)>(args)...);
ForEach<ComponentTypes...>::run<func>(std::forward<decltype(args)>(args)...);
}
};
template<typename CurrentComponentType>
struct ForEach<CurrentComponentType>
{
template<void (&func)(auto&&... args)>
static constexpr void run(auto&&... args)
{
func<CurrentComponentType>(std::forward<decltype(args)>(args)...);
}
};
I don't know how to take a template function as a (template but not necessarily) argument.
For some reasons that I don't understand, I cannot call again the run() function as so: run<func>(. It says '<unresolved overloaded function type>'.
I think there are multiple things I don't understand.
How can I fix it, and why doesn't it work this way? What am I misunderstanding?
Each of the solutions below can be used like so:
int main(void)
{
int i { 0 };
ForEach<int, float>::run<testFunc>(i);
}
Because you can't pass an uninstantiated template function as a (template) parameter, you need to make it a template class with an operator():
#include <utility>
template<typename T>
struct testFunc
{
void operator()(int& i) {}
};
template<typename T, typename... Ts>
struct ForEach
{
template<template<typename> typename F, typename... Args>
static constexpr void run(Args&&... args)
{
ForEach<T>::template run<F>(std::forward<Args>(args)...);
ForEach<Ts...>::template run<F>(std::forward<Args>(args)...);
}
};
template<typename T>
struct ForEach<T>
{
template<template<typename> typename F, typename... Args>
static constexpr void run(Args&&... args)
{
F<T>{}(std::forward<Args>(args)...);
}
};
Starting in C++17, you can use fold expressions to avoid recursion:
#include <utility>
template<typename T>
struct testFunc
{
void operator()(int& i) {}
};
template<typename... Ts>
struct ForEach
{
template<template<typename> typename F, typename... Args>
static constexpr void run(Args&&... args)
{
(F<Ts>{}(std::forward<Args>(args)...), ...);
}
};
Finally, in C++20 you also have the option to use a lambda with a template parameter list instead:
#include <utility>
auto testFunc = []<typename T>(int& i) {};
template<typename... Ts>
struct ForEach
{
template<auto F, typename... Args>
static constexpr void run(Args&&... args)
{
(F.template operator()<Ts>(std::forward<Args>(args)...), ...);
}
};

Q: Template specialization with parameter pack

I'll get right to the question.
We have template specialization:
class TestClass
{
public:
template<typename T>
static T fn(const T& a);
}
// OK
template<typename T>
T TestClass::fn(const T& a)
{
// ... magic for any type here ...
}
// OK
template<>
int TestClass::fn(const int& a)
{
// ... magic for int type here ...
}
All okay. But what if I want to add a parameter pack to the function?
class TestClass
{
public:
template<typename T, typename... Args>
static T fn(const T& a, Args&& ...b);
}
// OK
template<typename T, typename... Args>
T TestClass::fn(const T& a, Args&& ...b)
{
// ... magic for any type here ...
}
// Error
template<typename... Args>
int TestClass::fn(const int& a, Args&& ...b)
{
// ... magic for int type here ...
}
Visual Studio gives error E0147.
How can I do this without adding a new function to the class?
Thanks in advance for your help!
Have a nice day!
In your first example
template<>
int TestClass::fn(const int& a)
{ /* ... */ }
you have a full specialization, that is permitted for C++ template functions/methods
But, given the declaration
template<typename T, typename... Args>
static T fn(const T& a, Args&& ...b);
your second example
template<typename... Args>
int TestClass::fn(const int& a, Args&& ...b)
{ /* ... */ }
become a partial specialization, that isn't permitted for C++ functions/methods.
But you can use overloading, avoiding specialization at all, adding a declaration for a different template method with the same name.
I mean
class TestClass
{
public:
template <typename T, typename ... Args>
static T fn (T const & a, Args && ... b);
template <typename ... Args>
static T fn (int const & a, Args && ... b);
};
template <typename T, typename ... Args>
T TestClass::fn (T const & a, Args && ... b)
{ /* ... */ }
template <typename ... Args>
int TestClass::fn (int const & a, Args && ... b)
{ /* ... */ }

Passing vector items to function-object with unknown number of parameters

Here is a simplified version of what I am trying to achieve:
template <class Func, class Params>
void foo(Func f, Params p) {
f(p[0], p[1], ...) // <-- this is the problem. How to do this?
}
...
foo([](int a, int b){ cout<<(a+b); }, std::vector<int>{1,2});
foo([](char a){ cout<<a; }, std::vector<char>{'a'});
I hope the problem is clear.
EDIT:
The above example did not convey the problem well. I have a vector, populated at some earlier stage, of the parameters. I want a function that will accept a function-object and call it with the parameters from the vector. I can assume that the vector size is equal to the number of parameters.
Hopefully better example:
class C {
std::vector<int> v;
public:
void add_param(int);
... // other functions that manipulate the vector in various ways
template<class Func>
void run(Func f) {
f(v[0], etc...); // <-- problem
}
};
You can use variardic templates:
template <class Func, class... Params>
void foo(Func f, Params... p) {
f(p...);
}
foo([](int a, int b){ cout<<(a+b); }, 1, 2);
foo([](char a){ cout<<a; }, 'a');
You may use something like:
// Minimal traits to have information about function
template <typename Func> struct function_traits;
template <typename Ret, typename ... Ts>
struct function_traits<Ret (Ts...)>
{
constexpr static auto arity = sizeof...(Ts);
};
template <typename Ret, typename ... Ts>
struct function_traits<Ret (*)(Ts...)> : function_traits<Ret(Ts...)> {};
template <typename C, typename Ret, typename ... Ts>
struct function_traits<Ret (C::*)(Ts...) const> : function_traits<Ret(Ts...)> {};
template <typename C>
struct function_traits : function_traits<decltype(&C::operator())> {};
namespace detail
{
template <typename F, typename Vec, std::size_t ... Is>
void call(const F& f, Vec&& v, std::index_sequence<Is...>)
{
f(v[Is]...);
}
}
template <class Func, class Vec>
void foo(const Func& f, Vec&& v) {
detail::call(f,
std::forward<Vec>(v),
std::make_index_sequence<function_traits<Func>::arity>());
}
Demo

How to partition a parameter pack?

I'd like to write a function template, apply, which receives some function f, an integer i, and a parameter pack. apply needs to unpack the parameters and apply f to them, except for the ith parameter, pi. For pi, it needs to call some other function g before passing it as a parameter to f.
It seems that I need a way to partition the parameter pack into a left side, the ith parameter, and the right side. Is this possible? In code:
template<int i, typename Function, typename... Parms>
void apply(Function f, Parms... parms)
{
auto lhs = // what goes here?
auto pi = // what goes here?
auto rhs = // what goes here?
f(lhs..., g(pi), rhs...);
}
OK, here we go! It really ugly but I couldn't come up with a nicer version in a hurry ;) Most of the stuff is bog standard template specialization. The biggest issue is creating a list of integers of the proper size. I seem to recall that I came up with a nice version but somehow I can't recall what I did. Enjoy!
#include <iostream>
#include <utility>
// printing the values
void print_args() {}
template <typename F> void print_args(F f) { std::cout << f; }
template <typename F, typename... T>
void print_args(F f, T... args)
{
std::cout << f << ", ";
print_args(args...);
}
// the function object to be called:
struct Functor
{
template <typename... T>
void operator()(T... args)
{
std::cout << "f(";
print_args(args...);
std::cout << ")\n";
}
};
// conditionally apply g():
template <typename T> T g(T value) { return 1000 + value; }
template <int i, int j, typename T>
typename std::enable_if<i != j, T>::type forward(T t) { return t; }
template <int i, int j, typename T>
typename std::enable_if<i == j, T>::type forward(T t) { return g(t); }
// create a series of integers:
template <int... Values> struct values {};
template <int Add, typename> struct combine_values;
template <int Add, int... Values>
struct combine_values<Add, values<Values...>>
{
typedef values<Values..., Add> type;
};
template <int Size> struct make_values;
template <> struct make_values<0> { typedef values<> type; };
template <int Size>
struct make_values
{
typedef typename combine_values<Size, typename make_values<Size -1>::type>::type type;
};
// applying f(t...) except for ti where g(ti) is called
template <int i, int... Values, typename Function, typename... T>
void apply_aux(values<Values...>, Function f, T... t)
{
f(forward<i, Values>(t)...);
}
template <int i, typename Function, typename... T>
void apply(Function f, T... t)
{
apply_aux<i>(typename make_values<sizeof...(T)>::type(), f, t...);
}
int main()
{
apply<3>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8);
apply<4>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8);
apply<5>(Functor(), 1, 2, 3, 4, 5, 6, 7, 8);
}
Iactually did code something similar a little while ago. So try the following code:
template<unsigned N, unsigned M>
struct call_up_impl{
template<class Func, class Mutator, class Tuple, class... Args>
static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) {
call_up_impl<N-1, M>::do_call(func, mutator, args, std::get<N-1>(args), std::forward<Args>(unpacked_args)...);
}
};
template<unsigned M>
struct call_up_impl<0, M> {
template<class Func, class Mutator, class Tuple, class... Args>
static void do_call(const Func& func, const Mutator&, const Tuple&, Args&&... unpacked_args) {
func(std::forward<Args>(unpacked_args)...);
}
};
template<unsigned M>
struct call_up_impl<M, M> {
template<class Func, class Mutator, class Tuple, class... Args>
static void do_call(const Func& func, const Mutator& mutator, const Tuple& args, Args&&... unpacked_args) {
call_up_impl<M-1, M>::do_call(func, mutator, args, mutator(std::get<M-1>(args)), std::forward<Args>(unpacked_args)...);
}
};
template<int i, typename Function, typename... Parms>
void apply(Function f, Parms... parms) {
std::tuple<Parms...> t(parms...);
call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t);
}
This is a quick adaption of my original code, so it isn't thoroughly tested and maybe not the not optimal way to do this, but it should work at least (at least according to a quick test and depending what exactly you want). It should be possible to do this without the tuple, but I haven't gotten that to compile with g++ (it doesn't seem to like the nested variadic templates needed). However changing apply to:
template<int i, typename Function, typename... Parms>
void apply(Function f, Parms&&... parms) {
std::tuple<Parms&&...> t(std::forward<Parms>(parms)...);
call_up_impl<std::tuple_size<decltype(t)>::value, i + 1>::do_call(f, &g, t);
}
will probably avoid most of the overhead introduced by the tuple. It would be even better to make correct forwarding of the results of the std::get calls, but I'm too tired to work that out write now.

accessing first n variadic function arguments

I have the following code :
template<size_t sz,typename T=float> class Vec{
T v[sz];
Vec(const T& val,const T&... nv){
//how do i assign `sz` number of first arguments into `this->v` array
}
}
I want to create constructor, that receive generic number of constructor argument, and assign the first sz number of arguments into member variable of v
what I want to do, is to be able doing like this: Vec<3> var(1.0,2.0,3.0);
This is possible, but complicated. Here is some code that does it. It may be possible to eliminate the holder type, but I leave that as an exercise for the reader. This has been tested with g++ 4.6.
#include <iostream>
#include <typeinfo>
template<size_t ... Indices> struct indices_holder
{};
template<size_t index_to_add,typename Indices=indices_holder<> >
struct make_indices_impl;
template<size_t index_to_add,size_t...existing_indices>
struct make_indices_impl<index_to_add,indices_holder<existing_indices...> >
{
typedef typename make_indices_impl<
index_to_add-1,
indices_holder<index_to_add-1,existing_indices...> >::type type;
};
template<size_t... existing_indices>
struct make_indices_impl<0,indices_holder<existing_indices...> >
{
typedef indices_holder<existing_indices...> type;
};
template<size_t max_index>
typename make_indices_impl<max_index>::type make_indices()
{
return typename make_indices_impl<max_index>::type();
}
template<unsigned index,typename ... U>
struct select_nth_type;
template<unsigned index,typename T,typename ... U>
struct select_nth_type<index,T,U...>
{
typedef typename select_nth_type<index-1,U...>::type type;
static type&& forward(T&&,U&&... u)
{
return select_nth_type<index-1,U...>::forward(static_cast<U&&>(u)...);
}
};
template<typename T,typename ... U>
struct select_nth_type<0,T,U...>
{
typedef T type;
static type&& forward(T&&t,U&&...)
{
return static_cast<T&&>(t);
}
};
template<unsigned index,typename ... U>
typename select_nth_type<index,U...>::type&& forward_nth(U&&... u)
{
return static_cast<typename select_nth_type<index,U...>::type&&>(
select_nth_type<index,U...>::forward(
static_cast<U&&>(u)...));
}
template<size_t sz,typename T=float> struct Vec{
struct holder
{
T data[sz];
};
holder v;
template<typename ... U>
struct assign_helper
{
template<size_t... Indices>
static holder create_array(indices_holder<Indices...>,Vec* self,U&&... u)
{
holder res={{static_cast<T>(forward_nth<Indices>(u...))...}};
return res;
}
};
template<typename ... U>
Vec(U&&... u):
v(assign_helper<U...>::create_array(make_indices<sz>(),this,static_cast<U&&>(u)...))
{}
};
int main()
{
Vec<3> v(1.2,2.3,3.4,4.5,5.6,7.8);
std::cout<<"v[0]="<<v.v.data[0]<<std::endl;
std::cout<<"v[1]="<<v.v.data[1]<<std::endl;
std::cout<<"v[2]="<<v.v.data[2]<<std::endl;
}
I believe this satisfies all the requirements:
template <size_t sz,typename T,typename... Args> struct Assign;
template <typename T,typename First,typename...Rest>
struct Assign<1,T,First,Rest...> {
static void assign(T *v,const First &first,const Rest&... args)
{
*v = first;
}
};
template <size_t sz,typename T,typename First,typename... Rest>
struct Assign<sz,T,First,Rest...> {
static void assign(T *v,const First &first,const Rest&... rest)
{
*v = first;
Assign<sz-1,T,Rest...>::assign(v+1,rest...);
}
};
template<size_t sz,typename T=float>
struct Vec{
T v[sz];
template <typename... Args>
Vec(const T& val,const Args&... nv){
Assign<sz,T,T,Args...>::assign(v,val,nv...);
}
};
This is another technique which is much simpler if it is ok not to have at least sz parameters:
template<size_t sz,typename T=float>
struct Vec {
T v[sz];
template <typename... Args>
Vec(const T& val,const Args&... nv)
{
T data[] = {val,static_cast<const T &>(nv)...};
int i=0;
for (; i<sz && i<(sizeof data)/sizeof(T); ++i) {
v[i] = data[i];
}
for (; i<sz; ++i) {
v[i] = T();
}
}
};
First declare this utility function:
template <typename T> inline void push(T* p) {}
template <typename T, typename First, typename... Args>
inline void push(T* p, First&& first, Args&&... args)
{
*p = first;
push(++p, std::forward<Args>(args)...);
}
Then, in your class:
template<size_t sz,typename T=float>
class Vec
{
T v[sz];
template <typename... Args>
Vec(T first, Args&&... args) // << we have changed const T& to T&&
{
//how do i assign `sz` number of first arguments into `this->v` array
// like this:
push(&v[0], first, std::forward<Args>(args)...);
}
}
sz is a template argument, you can directly use it in your code.
The following could work:
template <typename T, std::size_t N>
struct Foo
{
T arr[N];
template <typename ...Args> Foo(Args &&... args) : arr{std::forward<Args>(args)...} { }
};
Usage:
Foo<int, 3> a(1,2,3);
This allows you to construct the array elements from anything that's convertible to T. You can obtain the number of parameters (which can be anything not exceeding N) with sizeof...(Args).
Can you make use of something like this?
template <typename... Args> class Vec {
std :: tuple <Args...> m_args;
Vec (const Foo & a, const Bar & b, Args&&... args)
: m_args (args...)
{
// ... something with a, b
}
};
There are a few rules to constrain you:
you can only have one template... Args-style packed argument list per template class
methods which use it must have the templated arguments on the right-hand-side
You need to unpack the argument pack while keeping a count and do the necessary runtime operation in a functor. This should get you started:
template<unsigned, typename...>
struct unroll;
template<unsigned size, typename Head, typename... Tail>
struct unroll<size, Head, Tail...> {
void operator()(Head&& h, Tail&&... tail) {
// do your stuff, pass necessary arguments through the ctor of the
// struct
unroll<size - 1, Tail...>()(std::forward<Tail>(tail)...);
}
};
template<typename Head, typename... Tail>
struct unroll<1, Head, Tail...> {
void operator()(Head&& h, Tail&&... tail) {
// do your stuff the last time and do not recurse further
}
};
int main()
{
unroll<3, int, double, int>()(1, 3.0, 2);
return 0;
}
The following almost works (and for the last N arguments instead of the first, but hey). Perhaps someone can help with the compile error in the comments below:
#include <iostream>
void foo (int a, int b) {
std :: cout << "3 args: " << a << " " << b << "\n";
}
void foo (int a, int b, int c) {
std :: cout << "3 args: " << a << " " << b << " " << c << "\n";
}
template <int n, typename... Args>
struct CallFooWithout;
template <typename... Args>
struct CallFooWithout <0, Args...> {
static void call (Args... args)
{
foo (args...);
}
};
template <int N, typename T, typename... Args>
struct CallFooWithout <N, T, Args...> {
static void call (T, Args... args)
{
CallFooWithout <N-1, Args...> :: call (args...);
// ambiguous class template instantiation for 'struct CallFooWithout<0, int, int, int>'
// candidates are: struct CallFooWithout<0, Args ...>
// struct CallFooWithout<N, T, Args ...>
}
};
template <int n, typename... Args>
void call_foo_with_last (Args... args)
{
CallFooWithout <sizeof...(Args)-n, Args...> :: call (args...);
}
int main ()
{
call_foo_with_last <2> (101, 102, 103, 104, 105);
call_foo_with_last <3> (101, 102, 103, 104, 105);
}
I don't see why it's ambiguous because 0 is more specialised than N so that should satisfy the partial order ?!?!?
By contrast, the below is fine.
template <int N, typename... T>
struct Factorial
{
enum { value = N * Factorial<N - 1,T...>::value };
};
template <typename... T>
struct Factorial<0, T...>
{
enum { value = 1 };
};
void foo()
{
int x = Factorial<4,int>::value;
}
What's the difference?