So I have some type X:
typedef ... X;
and a template function f:
class <typename T>
void f(X& x_out, const T& arg_in);
and then a function g:
void g(const X* x_array, size_t x_array_size);
I need to write a variadic template function h that does this:
template<typename... Args>
void h(Args... args)
{
constexpr size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
for (int i = 0; i < nargs; i++) // foreach arg
f(x_array[i], args[i]); // call f (doesn't work)
g(x_array, nargs); // call g with x_array
}
The reason it doesn't work is because you can't subscript args like that at runtime.
What is the best technique to replace the middle part of h?
And the winner is Xeo:
template<class T> X fv(const T& t) { X x; f(x,t); return x; }
template<class... Args>
void h(Args... args)
{
X x_array[] = { fv(args)... };
g(x_array, sizeof...(Args));
}
(Actually in my specific case I can rewrite f to return x by value rather than as an out parameter, so I don't even need fv above)
You could refactor or wrap f to return a new X instead of having it passed, since this would play pack expansion into the hand and make the function really concise:
template<class T>
X fw(T const& t){ X x; f(x, t); return x; }
template<class... Args>
void h(Args... args){
X xs[] = { fw(args)... };
g(xs, sizeof...(Args));
}
Live example.
And if you could change g to just accept an std::initializer_list, it would get even more concise:
template<class... Args>
void h(Args... args){
g({f(args)...});
}
Live example. Or (maybe better), you could also provide just a wrapper g that forwards to the real g:
void g(X const*, unsigned){}
void g(std::initializer_list<X> const& xs){ g(xs.begin(), xs.size()); }
template<class... Args>
void h(Args... args){
g({f(args)...});
}
Live example.
Edit: Another option is using a temporary array:
template<class T>
using Alias = T;
template<class T>
T& as_lvalue(T&& v){ return v; }
template<class... Args>
void h(Args... args){
g(as_lvalue(Alias<X[]>{f(args)...}), sizeof...(Args));
}
Live example. Note that the as_lvalue function is dangerous, the array still only lives until the end of the full expression (in this case g), so be cautious when using it. The Alias is needed since just X[]{ ... } is not allowed due to the language grammar.
If all of that's not possible, you'll need recursion to access all elements of the args pack.
#include <tuple>
template<unsigned> struct uint_{}; // compile-time integer for "iteration"
template<unsigned N, class Tuple>
void h_helper(X (&)[N], Tuple const&, uint_<N>){}
template<unsigned N, class Tuple, unsigned I = 0>
void h_helper(X (&xs)[N], Tuple const& args, uint_<I> = {}){
f(xs[I], std::get<I>(args));
h_helper(xs, args, uint_<I+1>());
}
template<typename... Args>
void h(Args... args)
{
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
h_helper(xs, std::tie(args...));
g(xs, nargs);
}
Live example.
Edit: Inspired by ecatmur's comment, I employed the indices trick to make it work with just pack expansion and with f and g as-is, without altering them.
template<unsigned... Indices>
struct indices{
using next = indices<Indices..., sizeof...(Indices)>;
};
template<unsigned N>
struct build_indices{
using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0>{
using type = indices<>;
};
template<unsigned N>
using IndicesFor = typename build_indices<N>::type;
template<unsigned N, unsigned... Is, class... Args>
void f_them_all(X (&xs)[N], indices<Is...>, Args... args){
int unused[] = {(f(xs[Is], args), 1)...};
(void)unused;
}
template<class... Args>
void h(Args... args){
static constexpr unsigned nargs = sizeof...(Args);
X xs[nargs];
f_them_all(xs, IndicesFor<nargs>(), args...);
g(xs, nargs);
}
Live example.
Nice template as answer for first part of question:
template <class F, class... Args>
void for_each_argument(F f, Args&&... args) {
[](...){}((f(std::forward<Args>(args)), 0)...);
}
It's obvious: you don't use iteration but recursion. When dealing with variadic templates something recursive always comes in. Even when binding the elements to a std::tuple<...> using tie() it is recursive: It just happens that the recursive business is done by the tuple. In your case, it seems you want something like this (there are probably a few typos but overall this should work):
template <int Index, int Size>
void h_aux(X (&)[Size]) {
}
template <int Index, int Size, typename Arg, typename... Args>
void h_aux(X (&xs)[Size], Arg arg, Args... args) {
f(xs[Index], arg);
h_aux<Index + 1, Size>(xs, args...);
}
template <typename... Args>
void h(Args... args)
{
X xs[sizeof...(args)];
h_aux<0, sizeof...(args)>(xs, args...);
g(xs, sizeof...(args));
}
I think you won't be able to use nargs to define the size of the array either: Nothing indicates to the compiler that it should be a constant expression.
It's fairly simple to do with parameter pack expansion, even if you can't rewrite f to return the output parameter by value:
struct pass { template<typename ...T> pass(T...) {} };
template<typename... Args>
void h(Args... args)
{
const size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
X *x = x_array;
int unused[]{(f(*x++, args), 1)...}; // call f
pass{unused};
g(x_array, nargs); // call g with x_array
}
It should be possible just to write
pass{(f(*x++, args), 1)...}; // call f
but it appears g++ (4.7.1 at least) has a bug where it fails to order the evaluation of brace-initializer-list parameters as class initialisers. Array initialisers are OK though; see Sequencing among a variadic expansion for more information and examples.
Live example.
As an alternative, here's the technique mentioned by Xeo using a generated index pack; unfortunately it does require an extra function call and parameter, but it is reasonably elegant (especially if you happen to have an index pack generator lying around):
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;
template<typename... Args, int... i>
void h2(index<i...>, Args... args)
{
const size_t nargs = sizeof...(args); // get number of args
X x_array[nargs]; // create X array of that size
pass{(f(x_array[i], args), 1)...}; // call f
g(x_array, nargs); // call g with x_array
}
template<typename... Args>
void h(Args... args)
{
h2(indexer<sizeof...(args)>(), std::forward<Args>(args)...);
}
See C++11: I can go from multiple args to tuple, but can I go from tuple to multiple args? for more information.
Live example.
Xeo is onto the right idea- you want to build some kind of "variadic iterator" that hides a lot of this nastiness from the rest of the code.
I'd take the index stuff and hide it behind an iterator interface modeled after std::vector's, since a std::tuple is also a linear container for data. Then you can just re-use it all of your variadic functions and classes without having to have explicitly recursive code anywhere else.
Related
I want to retrieve index of each parameter from variadic template parameters, currently I am using this approach:
From third party library:
struct statement {
template <typename T>
void bind(int, T t) { // ....
}
};
My code:
template <unsigned Index, typename T>
void bind(statement& stmt, T t) {
stmt.bind(Index, t);
}
template <unsigned Index, typename T, typename... Args>
void bind(statement& stmt, T t, Args... args) {
bind<Index>(stmt, t);
bind<Index + 1>(stmt,args...);
}
template <typename... Args>
void bind_all(statement& stmt, Args... args) {
constexpr int Index = 0;
bind<Index>(stmt, args...);
}
Usage:
statement stmt;
prepare(stmt, "insert into tab (a,b,c,d,e,f) values(?,?,?,?,?,?)");
bind_all(stmt, 1,1.24f, 3.14, "Hello", std::string{"World"}, true);
My question: Is there a better way to achieve this, to get ordinal numbers of variadic template parameters?
Edit:
I want to use this implementation to wrap sql prepared statement and to bind specific parameter to specific index.
Here is an example of code that I want to wrap, instead of listing each bind individually, I want to call bind_all
prepare(stmt, "insert into tab (a, b) values (?, ?);");
const int eight_int = 8;
stmt.bind(0, &eight_int);
const string eight_str = "eight";
stmt.bind(1, eight_str.c_str());
execute(stmt);
With simple expansion (could use a fold expression in C++17)
struct statement
{
template<class T>
void bind(int index, T&& arg)
{
// magic
}
};
template<class... Args>
void BindAll(statement& stmt, Args&&... args)
{
using swallow = int[];
int idx = 0;
(void)swallow{0, (void (stmt.bind(idx++, std::forward<Args>(args))), 0)...};
}
I took some liberties with the API, but I think it maps close enough to your code.
Usage:
statement stmt;
BindAll(stmt, 1, 1.2, 1.3f, true, "abc");
Demo
Why not use a std::tuple for this.
#include <utility>
#include <tuple>
template<typename T, std::size_t... Index>
void doBind(Statement& st, T const& tuple, std::index_sequence<Index...> const&)
{
// Using C++17 fold expression
((st.bind(Index, std::get<Index>(tuple))),...);
// Using C++11 dummy variable
int dummy[] = {0, (st.bind(Index, std::get<Index>(tuple)),0)...};
(void)dummy; // to prevent unused variable warning.
}
template<typename... Args>
void prepare(std::string const& sql, Args&&... args)
{
Statement statement;
prepare(statement, sql);
doBind(statement, std::make_tuple(args...), std::make_index_sequence<sizeof...(args)>());
execute(statement);
}
You could use std::index_sequence to create a second template parameter pack containing the matching indices:
template <typename... Args, size_t... Is>
void bind_all_helper(std::index_sequence<Is...>, Args... args) {
int dummy[]{(bind<Is>(args), 0)...};
(void)dummy; // just to avoid unused variable warnings
}
template <typename... Args>
void bind_all(Args... args) {
bind_all_helper(std::make_index_sequence<sizeof...(args)>{}, args...);
}
Live Demo
This uses a dummy array definition along with the comma operator to create a sequence of calls to bind. For example, given bind_all(1, 3.14), the array definition would expand to something like this:
int dummy[] {
(bind<0>(1), 0),
(bind<1>(3.14), 0)
};
Each element of the array ends up being 0, but its evaluation has the side-effect of calling bind<N>(arg).
With C++17 the dummy array definition could be replaced with a fold expression, but that obviously isn't an option if you're limited to C++14.
I'm having trouble unrolling and forwarding a parameter pack of std::arrays to another function
Suppose we have a function that takes a single std::array and I want to unroll it and pass it as an argument to some other function I can do so by doing this:
template<typename T, typename...Ts>
void other_function(T, Ts...) { /* Do stuff with Ts */ }
template<typename T, size_t Size, size_t... I>
void forward_array(std::array<T, Size>& array_arg, std::index_sequence<I...>)
{
other_function(array_arg[I]...);
// for Size == 3 let's say we get the same thing as we would write
// other_function(array_arg[0], array_arg[1], array_arg[2]
// I skipped the std::forward
}
Now let's say we have a function that does this same thing, but it takes multiple arrays that can be of different size.
template<typename T, size_t... Sizes /*, size_t... I_Sequence0, size_t... I_Sequence1, ... I_SequenceN */>
void forward_many_arrays(std::array<T, Sizes>&... array_args /*, ???*/)
{
other_func( /* ??? */);
}
I want to unfold each array_arg and pass it to other_func, but how do I do that exactly here?. We would need a way to index into each array arg.
In my actual program, I have a class that has a member std::array of std::reference_wrapper which is not default constructable and I'm trying to provide an alternative constructor for that class that takes any number of arrays&, where the sum of their sizes matches the member array size and delegate it to the explicit constructor that takes T references, but I'm kind of stuck cause I don't know how to handle the unrolling.
You might have a "generic" getter
template <std::size_t I, typename Container, typename ... Containers>
decltype(auto) get(Container&& container, Containers&&...containers)
{
constexpr std::size_t size = std::tuple_size_v<std::decay_t<Container>>;
if constexpr (I < size) {
return container[I];
} else {
return get<I - size>(containers...);
}
}
Used like:
template <typename...Ts>
void other_function(Ts... ts) { ((std::cout << ts << " "), ...); }
template<typename... Ts, size_t... Is>
void forward_many_arrays(std::index_sequence<Is...>, Ts&&...ts)
{
other_function(get<Is>(ts...)...);
}
template<typename... Ts>
void forward_many_arrays(Ts&&...ts)
{
forward_many_arrays(std::make_index_sequence<(std::tuple_size_v<std::decay_t<Ts>> + ...)>(), ts...);
}
Demo
An implementation based on simple recursion:
template<std::size_t n, class Fn, class T, class... Ts>
void apply_all_impl(Fn fn, T& t, Ts&... ts) {
if constexpr (n == 0)
fn(t, ts...);
else
std::apply([&](auto&... args) {
apply_all_impl<n - 1>(fn, ts..., args...);
}, t);
}
template<class Fn, class... Ts>
void apply_all(Fn fn, Ts&... ts) {
apply_all_impl<sizeof...(Ts)>(fn, ts...);
}
Usage example:
std::array<int, 3> arr1{1, 2, 3};
std::array<int, 4> arr2{4, 5, 6, 7};
auto print_all = [](auto... ts) { (std::cout << ... << ts); };
apply_all(print_all, arr1, arr2); // Output: 1234567
Demo
I am in search of a ::std::function usable in constexpr.
Use case: I have a function which takes a function pointer as an argument, and a second which passes a lambda to the first function. Both are fully executable at compile time, so I want to constexpr them.
Eg:
template <class _Type>
class ConstexprFunctionPtr
{
private:
using Type = typename ::std::decay<_Type>::type;
const Type function;
public:
constexpr inline
ConstexprFunctionPtr(const Type f)
: function(f)
{ }
template <typename... Types>
constexpr inline
auto
operator() (Types... args)
const {
return function(args... );
}
};
constexpr inline
void
test()
{
ConstexprFunctionPtr<int(int)> test([](int i) -> int {
return i + 1;
});
int i = test(100);
ConstexprFunctionPtr<int(int)> test2([=](int i) -> int {
return i + 1;
});
i = test2(1000);
}
However, this only works because I am converting the lambda to a function pointer, and of course fails with capturing lambdas as showed in the second example. Can anyone give me some pointers on how to do that with capturing lambdas?
This would demonstrate the usecase:
constexpr
void
walkOverObjects(ObjectList d, ConstexprFunctionPtr<void(Object)> fun) {
// for i in d, execute fun
}
constexpr
void
searchObjectX(ObjectList d) {
walkOverObjects(d, /*lambda that searches X*/);
}
Thanks,
jack
Update:
Thanks for pointing out the C++20 solution, however, I want one that works under C++14
So a lot has changed with C++20 --- most importantly, you can now use dynamic memory and virtual functions within constexpr contexts. This makes it entirely possible to build a constexpr version of std::function. Here's a proof-of-concept (it's long and has no copy or move constructors, so please do not use this as-is). It compiles under clang 10, running code here. I've not tried it under other compilers, and it's worth noting that none of the major compilers claim to have a complete implementation of C++-20 at this time.
#include <type_traits>
#include <utility>
#include <functional>
template<typename Ret, typename... Args> struct _function{
constexpr virtual Ret operator()(Args...) const = 0;
constexpr virtual ~_function() = default;
};
template<typename F, typename Ret, typename... Args> struct _function_impl : public _function<Ret,Args...>{
F f;
constexpr Ret operator()(Args... args) const override {
return f(std::forward<Args>(args)...);
}
constexpr _function_impl(F&& f):f(f){}
};
template<typename > struct function;
template<typename Ret, typename... Args> struct function<Ret (Args...)>{
_function<Ret,Args...> *real_f{nullptr};
constexpr Ret operator()(Args... args) const {
return real_f->operator()(std::forward<Args>(args)...);
}
constexpr ~function(){
if (real_f) delete real_f;
}
template<typename F>
constexpr function(F&& f):real_f(new _function_impl<std::decay_t<F>,Ret,Args...>(std::move(f))){}
};
template<typename Ret, typename... Args>
constexpr Ret call_f_2(const function<Ret(Args...)> &f, Args... a){
return f(std::forward<Args>(a)...);
}
template<typename F, typename... Args>
constexpr decltype(auto) call_f(F && f, Args&&... a){
using Ret = std::invoke_result_t<std::decay_t<F>,Args...>;
function<Ret(Args...)> f2 = std::move(f);
return call_f_2<Ret,Args...>(f2,a...);
}
int main(){
constexpr int c = 3;
constexpr int i = call_f([c](int j) constexpr {return c + j;},4);
return i;
}
I am in search of a ::std::function usable in constexpr
Stop right here. it's impossible. std::function is a polymorphic wrapper function. stateless lambdas, statefull lambdas, functors, function pointers, function references - all of them can build a valid std::function that can change during runtime. so making a compile time equivalent is just a waste of time.
If you just want a compile time generic function parameter, you can just use templates
template<class functor_type>
class my_generic_function_consumer_class{
using decayed_function_type = typename std::decay_t<functor_type>;
decayed_function_type m_functor;
};
In your code in question, just accept a generic functor, and validate it using static_assert:
template<class function_type>
constexpr void walkOverObjects(ObjectList d, function_type&& fun) {
static_assert(std::is_constructible_v<std::function<void(ObjectList), function_type>>,
"function_type given to walkOverObjects is invalid.");
}
How the compiler interpret the symbol _1, and how the binding take place?
Consider the following example:
class A {
public:
boost::function<void (int x)> g;
};
class B {
public:
B() {}
static void foo(int i) { cout << "Hack: " << i <<endl; }
};
int main() {
A a;
a.g = boost::bind(B::foo,_1);
a.g(2);
return 0;
}
What magic happens internally in the line boost::bind(B::foo,_1);?
And how _1 is maped to the argument passed in the next line a.g(2);?
Output: Hack: 2
I will explain to the best of my ability. First and foremost, _1 is nothing but a global variable. There is nothing special about it in this regard, and it could be named anything else as well - placeholder1, or SergeyA. However, name like _1 is short, has well-understood meaning, and begins with _, which reduces likelihood of it clashing with other global names in the program.
The magic is in the type of this variable. It has a special type, which is reflected in generated bind* object. Later, when operator() is called, the type is recognized to take an argument from operator() arguments.
Here is some illustrating C++-like pseudocode, which is not correct, but is illustrative:
template<class F, class... ARG>
struct bound {
bound(F f, ARGS&&... args) : bound_args(args...), functor(f) { }
std::tuple<ARG...> bound_args;
template<class... T>
void operator()(T&&... args);
F f;
};
template<class F, class... T>
auto bind(F f, T&& args) {
return bound<std::remove_reference_t<T>...>(f, args...);
}
Now, let's introduce a placeholder type.
template<size_t N>
struct placeholder {
enum { position = N; };
template<class...T>
auto operator()(T&&... args) {
return std::get<position>(std::make_tuple(arg...));
}
};
placeholder<0> _1;
placeholder<1> _2;
So far so good. Now, let's see how the operator() actually works on bound object:
template<class... BOUND_ARGS>
template<class... CALL_ARGS>
void bound_object<BOUND_ARGS...>::operator() (CALL_ARGS&&... args) {
call_impl(args..., make_index_sequence<sizeof...(BOUND_ARGS)>{});
}
make_index_sequence here is needed to extract tuple values into function arguments, so do not pay too much attention to it. And here is call_impl;
template<class... BOUND_ARGS>
template<class... CALL_ARGS, size_t... ix>
void bound_object<BOUND_ARGS...>::call_impl(CALL_ARGS&&... args, std::index_sequence<ix...>) {
f(to_arg().(std::get<ix>(bound_args), args...)...);
}
And the last piece of puzzle is to_arg:
template<class B, class... ARGS>
auto to_arg(B&& b, ARGS... args) {
return b;
}
template<class... ARGS>
auto to_arg(placeholder<0> p, ARGS&&... args) {
return p(args);
}
template<class... ARGS>
auto to_arg(placeholder<1> p, ARGS&&... args) {
return p(args);
}
The whole of to_arg here is to give you either the bound argument or one of the supplied arguments, based on the bound argument type. In my example above, I used 3 overloads since you can partially specialize a function, but of course, it would make more sense to put it in a class and partially specialize the class.
I'm trying to make this program compile properly:
#include <vector>
#include <iostream>
int f(int a, int b)
{
::std::cout << "f(" << a << ", " << b << ") == " << (a + b) << '\n';
return a + b;
}
template <typename R, typename V>
R bind_vec(R (*f)(), const V &vec, int idx=0)
{
return f();
}
template <typename R, typename V, typename Arg1, typename... ArgT>
R bind_vec(R (*f)(Arg1, ArgT...), const V &vec, int idx=0)
{
const Arg1 &arg = vec[idx];
auto call = [arg, f](ArgT... args) -> R {
return (*f)(arg, args...);
};
return bind_vec(call, vec, idx+1);
}
int foo()
{
::std::vector<int> x = {1, 2};
return bind_vec(f, x);
}
Ideally I'd like bind_vec to take an arbitrary functor as an argument instead of just a function pointer. The idea is to pull the function arguments from a ::std::vector at compile time.
This isn't the final use for this, but it's a stepping stone to where I want to go. What I'm really doing is generating wrapper functions that unwrap their arguments from promises in a future/promise type system at compile time. These wrapper functions will themselves be promises.
In my ultimate use-case I can count on the functors being ::std::functions. But it would be nice to have an idea of how it should work for more general functors as well since I think this is a broadly interesting problem.
OK, first off, detecting the arity of a functor can be done, but it's a bit involved and best left to a separate question. Let's assume you will specify the arity of the functor in the call. Similarly, there are ways to obtain the return type of a callable object, but that's also beyond the scope of this question. Let's just assume the return type is void for now.
So we want to say,
call(F f, C v);
and that should say f(v[0], v[1], ..., v[n-1]), where f has arity n.
Here's an approach:
template <unsigned int N, typename Functor, typename Container>
void call(Functor const & f, Container const & c)
{
call_helper<N == 0, Functor, Container, N>::engage(f, c);
}
We need the helper:
#include <functional>
#include <cassert>
template <bool Done, typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper
{
static void engage(Functor const & f, Container const & c)
{
call_helper<sizeof...(I) + 1 == N, Functor, Container,
N, I..., sizeof...(I)>::engage(f, c);
}
};
template <typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper<true, Functor, Container, N, I...>
{
static void engage(Functor const & f, Container const & c)
{
assert(c.size() >= N);
f(c[I]...);
}
};
Example:
#include <vector>
#include <iostream>
void f(int a, int b) { std::cout << "You said: " << a << ", " << b << "\n"; }
struct Func
{
void operator()(int a, int b) const
{ std::cout << "Functor: " << a << "::" << b << "\n"; }
};
int main()
{
std::vector<int> v { 20, 30 };
call<2>(f, v);
call<2>(Func(), v);
}
Notes: In a more advanced version, I would deduce the arity of the callable object with some more template machinery, and I would also deduce the return type. For this to work, you'll need several specializations for free functions and various CV-qualified class member functions, though, and so this would be getting too large for this question.
Something like this is easily possible for (member) function pointers, but for functors with potentially overloaded operator(), this gets a dang lot harder. If we assume that you have a way to tell how many arguments a function takes (and assume that the container actually has that many elements), you can just use the indices trick to expand the vector into an argument list, for example with std::next and a begin() iterator:
#include <utility>
#include <iterator>
template<class F, class Args, unsigned... Is>
auto invoke(F&& f, Args& cont, seq<Is...>)
-> decltype(std::forward<F>(f)(*std::next(cont.begin(), Is)...))
{
return std::forward<F>(f)(*std::next(cont.begin(), Is)...);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
This implementation works really nice for random-access containers, but not so well for forward and especially input ones. To make those work in a performant fashion, you might try to go the route of incrementing the iterator with every expanded step, but you'll run into a problem: Evaluation order of arguments to a function is unspecified, so you'll very likely pass the arguments in the wrong order.
Luckily, there is a way to force evaluation left-to-right: The list-initialization syntax. Now we just need a context where that can be used to pass arguments, and a possible one would be to construct an object, pass the function and the arguments through the constructor, and call the function in there. However, you lose the ability to retrieve the returned value, since constructors can't return a value.
Something I thought of is to create an array of iterators, which point to the correct element, and expanding those again in a second step where they are dereferenced.
#include <utility>
template<class T> using Alias = T; // for temporary arrays
template<class F, class It, unsigned N, unsigned... Is>
auto invoke_2(F&& f, It (&&args)[N], seq<Is...>)
-> decltype(std::forward<F>(f)(*args[Is]...))
{
return std::forward<F>(f)(*args[Is]...);
}
template<class F, class Args, unsigned... Is>
auto invoke_1(F&& f, Args& cont, seq<Is...> s)
-> decltype(invoke_2(std::forward<F>(f), std::declval<decltype(cont.begin())[sizeof...(Is)]>(), s))
{
auto it = cont.begin();
return invoke_2(std::forward<F>(f), Alias<decltype(it)[]>{(void(Is), ++it)...}, s);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
The code was tested against GCC 4.7.2 and works as advertised.
Since you said that the functors you are getting passed are std::functions, getting the number of arguments they take is really easy:
template<class F> struct function_arity;
// if you have the 'Signature' of a 'std::function' handy
template<class R, class... Args>
struct function_arity<R(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>{};
// if you only have the 'std::function' available
template<class R, class... Args>
struct function_arity<std::function<R(Args...)>>
: function_arity<R(Args...)>{};
Note that you don't even need function_arity to make invoke from above work for std::function:
template<class R, class... Ts, class Args>
R invoke(std::function<R(Ts...)> const& f, Args& cont){
return invoke_1(f, cont, gen_seq<sizeof...(Ts)>{})
}
I managed to do what you want. It's simplest to explain if I leave it as not deducing the correct return type at first, I'll show how to add that later on:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),void>::type
{
f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),void>::type
{
bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}
There are two versions of this bind_vec - one is enabled if the parameter pack is the right size for the function. The other is enabled if it is still too small. The first version simply dispatches the call using the parameter pack, whilst the second version gets the next element (as determined by the size of the parameter pack) and recurses.
There SFINAE is done on the return type of the function in order that it not interfer with the deduction of the types, but this means it needs to be done after the function since it needs to know about F. There's a helper function that finds the number of arguments needed to call a function pointer.
To deduce the return types also we can use decltype with the function pointer:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),decltype(f(std::forward<Args>(args)...))>::type
{
return f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),decltype(bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args))))>::type
{
return bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}