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
Related
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)
{ /* ... */ }
Suppose I have a function like this
template <typename... FunctionList>
void call_all (int i, float f, const FunctionList... function_list);
template <>
void call_all (int, float)
{
}
I want to specialize it something like this:
template <typename HasIntArgument, typename... FL>
void call_all (int i, float f, const HasIntArgument & hia, const FL... list)
{
hia (i);
call_all (i, f, list...);
}
template <typename HasFloatArgument, typename... FL>
void call_all (int i, float f, const HasFloatArgument & hfa, const FL... list)
{
hfa (f);
call_all (i, f, list...);
}
In words, I want this function to, for each function-like object in function_list, determine whether it is callable with signature void(int) or void(float). (Nothing in this list will be callable with more than one signature.)
I want this to work with raw function pointers, lambdas, or anything with a suitable operator().
Can I write a suitable specialization directly, or do I have to do weird stuff with traits classes and SFINAE?
You might do something like:
#if 0 // C++17
template <typename F>
void dispatch(F func, int i, float f)
{
if constexpr (has_int_argument<F>::value) {
func(i);
} else {
func(f);
}
}
#else // C++11
template <typename F>
typename std::enable_if<has_int_argument<F>::value>::type
dispatch(F func, int i, float)
{
func(i);
}
template <typename F>
typename std::enable_if<!has_int_argument<F>::value>::type
dispatch(F func, int, float f)
{
func(f);
}
#endif
template <typename... Fs>
void call_all (int i, float f, const Fs&... fs)
{
// (dispatch(fs, i, f), ...); // C++17
const int dummy[] = {0, (dispatch(fs, i, f), 0)...};
static_cast<void>(dummy);
}
With appropriate function traits has_int_argument. something like:
template <typename ClassOrSig> struct funct_trait;
template <typename C>
struct funct_trait : funct_trait<decltype(&C::operator())> {};
template <typename C, typename Ret, typename ...Args>
struct funct_trait<Ret (C::*) (Args...)> : funct_trait<Ret(Args...)> {};
template <typename C, typename Ret, typename ...Args>
struct funct_trait<Ret (C::*) (Args...) const> : funct_trait<Ret(Args...)> {};
// &&, &, volatile, ... (C ellipsis)
template <typename Ret, typename ...Args>
struct funct_trait<Ret (*)(Args...)> : funct_trait<Ret(Args...)> {};
template <typename Ret, typename ...Args>
struct funct_trait<Ret (Args...)>
{
using sig_type = Ret(Args...);
using args_tuple = std::tuple<Args...>;
// ...
};
template <typename T>
using has_int_argument = std::is_same<std::tuple<int>,
typename funct_trait<T>::args_tuple>;
Demo
template<class...Fs>struct overloaded:Fs...{
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs...)->overloaded<Fs...>;
the above is a bit trickier in c++14, but implementations exist all over the place.
namespace details {
struct secret_tag {};
struct secret_result {
template<class...Ts>
secret_tag operator()(Ts&&...) const;
};
template<class F>
using secret_tester = overloaded<std::decay_t<F>, secret_result>;
}
template<class F, class Arg>
using match_arg_exactly = std::integral_constant<
bool,
!std::is_same<
details::secret_tag,
std::result_of_t< details::secret_tester<F>(Arg) >
>{}
>;
now we can ask for a given object if it can match a specific argument exactly.
template <typename HasIntArgument>
void call_one(int i, float f, std::true_type, const HasIntArgument & hia)
{
hia (i);
}
template <typename HasFloatArgument>
void call_one(int i, float f, std::false_type, const HasFloatArgument& hia)
{
hia (f);
}
template <typename F>
void call_one(int i, float f, const F & hia)
{
call_one( i, f, match_arg_exactly<const F&, int>{}, hia );
}
and we use this:
void call_all (int, float)
{}
template<class F, class...Fs>
void call_all (int i, float f, F const& f0, Fs const&...fs) {
call_one( i, f, f0 );
call_all(i, f, fs...);
}
Test code:
struct float_eater {
void operator()(float x)const{ std::cout<< "float "<<x<<"\n"; }
};
struct int_eater {
void operator()(int x)const{ std::cout<< "int "<<x<<"\n"; }
};
call_all( 42, 3.14, float_eater{}, int_eater{}, int_eater{} );
Live example
A c++14 overloaded is something like:
template<class...Fs>
struct overloaded;
template<class F0>
struct overloaded<F0>:F0 {
overloaded(F0 f0):F0(std::move(f0)) {}
using F0::operator();
};
template<class F0, class F1>
struct overloaded<F0, F1>: F0, F1 {
overloaded( F0 f0, F1 f1 ):F0(std::move(f0)), F1(std::move(f1)) {}
using F0::operator();
using F1::operator();
};
template<class F0, class...Fs>
struct overloaded<F0, Fs...>:
overloaded<F0, overloaded<Fs...>>
{
overloaded(F0 f0, Fs...fs):
F0(std::move(f0)),
overloaded<Fs...>( std::move(fs)... )
{}
};
which I think is sufficient for our purposes. (More generally, you either make a binary tree, balanced or not), and handle perfect forwarding, and... etc.
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);
I have a typelist. I would like to create a tuple with the results of calling a function on each type in that list and then use that as arguments to another functor. So something like this:
template<typename F>
struct function_traits;
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
using return_type = R;
using param_types = std::tuple<Args...>;
};
template<typename T> struct function_traits : public
function_traits<decltype(&T::operator())> {};
template <typename T>
T* get_arg(int id)
{
// Actual implementation omitted. Uses the id parameter to
// do a lookup into a table and return an existing instance
// of type T.
return new T();
}
template <typename Func>
void call_func(Func&& func, int id)
{
using param_types = function_traits<Func>::param_types>;
func(*get_arg<param_types>(id)...); // <--- Problem is this line
}
call_func([](int& a, char& b) { }, 3);
The problem is that func(*get_arg<param_types>(id)...); doesn't actually compile since param_types is a tuple and not a parameter pack. The compiler generates this error: "there are no parameter packs available to expand". What I would liked to have happened is for that line to expand to:
func(*get_arg<int>(id), *get_arg<char>(id));
And to have that work for any number of arguments. Is there any way to get that result?
This question seems similar but does not solve my problem by itself: "unpacking" a tuple to call a matching function pointer. I have a type list and from that I want to generate a list of values to use as function arguments. If I had the list of values I could expand them and call the function as outlined in that question, but I do not.
Not sure that is what do you want.
I don't know how to expand, inside call_func(), the parameters pack of params_type but, if you afford the use of a helper struct and a compiler with C++14...
I've prepared the following example with support for return type.
#include <tuple>
template<typename F>
struct function_traits;
template<typename T, typename R, typename... Args>
struct function_traits<R(T::*)(Args...) const> {
using return_type = R;
using param_types = std::tuple<Args...>;
};
template<typename T> struct function_traits : public
function_traits<decltype(&T::operator())> {};
template <typename T, typename ... Args>
T get_arg (std::tuple<Args...> const & tpl)
{ return std::get<typename std::decay<T>::type>(tpl); }
template <typename ...>
struct call_func_helper;
template <typename Func, typename Ret, typename ... Args>
struct call_func_helper<Func, Ret, std::tuple<Args...>>
{
template <typename T, typename R = Ret>
static typename std::enable_if<false == std::is_same<void, R>::value, R>::type
fn (Func const & func, T const & t)
{ return func(get_arg<Args>(t)...); }
template <typename T, typename R = Ret>
static typename std::enable_if<true == std::is_same<void, R>::value, R>::type
fn (Func const & func, T const & t)
{ func(get_arg<Args>(t)...); }
};
template <typename Func,
typename T,
typename R = typename function_traits<Func>::return_type>
R call_func (Func const & func, T const & id)
{
using param_types = typename function_traits<Func>::param_types;
return call_func_helper<Func, R, param_types>::fn(func, id);
}
int main()
{
call_func([](int const & a, char const & b) { }, std::make_tuple(3, '6'));
return 0;
}
Hope this helps.
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.