How to use std::function using variadic template - c++

There is a template for constructing std::function:
template< class R, class... Args >
class function<R(Args...)>;
I have not figured out how to invoke it. (VC++, if that matters.)
Question: How can I use std::function with a variadic list without using std::bind?
#include <functional>
#include <iostream>
using vfunc = std::function<void()>;
using namespace std; // I know, I know.
template<class F, class... Args>
void
run(F&& f, Args&&... args) {
vfunc fn = bind(forward<F>(f), forward<Args>(args)...); //OK
//vfunc fn = vfunc(forward<F>(f), forward<Args>(args)...); // COMPILER ERROR
fn();
}
void foo(int x) {
cout << x << " skidoo\n";
}
int main() {
run(foo, 23);
return 0;
}

There is a template for constructing std::function.
template< class R, class... Args >
class function<R(Args...)>;
That's not what that declaration means. It's not declaring a constructor or a "template for constructing" anything; it's a specialization for the template class std::function. The specialization is the only definition of std::function; the base template is never defined. I think the point of this has something to do with using a function signature in the template declaration. That is, being able to use the template via function rather than as function.
You want to take a callable object and some number of values and create a new callable object that stores those values, which has an operator() overload that calls the given function with those values. std::function does not do that; it has no constructors for doing so.
This is exactly what std::bind is for. Basically, your code is fine as is: storing the result of bind within function is entirely valid.

In that case, you can just wrap the function in a lambda and construct your std::function from it.
template<class F, class... Args>
void run(F&& f, Args&&... args) {
auto fn = vfunc{
[=]() mutable {
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
};
fn(); // fn is of type std::function<void()>
}
I made the lambda mutable so std::forward will not silently not move.
Note however that the [=] capture will copy everything. To support move only types, you can use a tuple:
[f = std::forward<F>(f), args = std::tuple{std::forward<Args>(args)...}]() mutable {
std::apply(std::forward<F>(f), std::move(args));
}
In C++20, this becomes easier:
[f = std::forward<F>(f), ...args = std::forward<Args>(args)...]() mutable {
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}

Related

How to convert a constructor to a std::function [duplicate]

This question already has answers here:
How to pass a function pointer that points to constructor?
(8 answers)
Construct std::function with a constructor based on template
(1 answer)
Closed 3 years ago.
Is there any way to assign a constructor to a function like 'f':
struct C
{
C(int){};
};
auto f = C::C(int); // not work
auto g = [](int){ return C(int()); }; // works
Neither C, C::C, &C, &C::C, C::&C, C::C(int), &C::C(int) ... works
Solution proposed by Friday Pie:
template <class T>
struct ConstructHelper
{
template <class... Args>
static T&& construct(Args&&... args)
{
return std::move(T(std::forward<Args>(args)...));
}
};
auto f = ConstructHelper<C>::construct<int>; // works
auto c = apply(f, 0); // works
The code you tried to write follows other rules than than the lambda that you wrote.
In the first one, you are trying to get a pointer to a member function: &C::C This would be similar to &C::print (assuming argument int) The first argument of this function would be a pointer to C, the second would the the int.
However, we are trying to do this for the constructor. So we don't have a valid C to work on. The result is that this simply doesn't compile.
Note that if you do want to execute a constructor on existing memory, you need placement new.
Your second code is a lambda. In short: a class with operator() implemented. And in this operator, you write code as in any other function and return a newly constructed instance by value. (Although, this looks a lot like a vexing parse) Tis is similar to executing the print function that was mentioned before.
So both would have different semantics and your compiler is right in failing to compile this code.
In theory your hypothetical function apply would look quite simple as a template
#include <iostream>
#include <type_traits>
struct C
{
C(int){};
};
template <class F, class... Args>
auto apply ( F&& f, Args&&... args) -> typename std::result_of<F(Args...)>::type
{
return f(args...);
}
float foo (int a, float b) { return a*b; }
int main()
{
auto b = apply(&foo, 3, 5.f);
//auto b = apply(&C::C, 3); //error: taking address of constructor 'C::C'
return 0;
}
But it is impossible to take address of constructor, as per the ISO standard. In most cases this special function is a non-entity in resulting code.
Neither explicit call to constructor is allowed. Your lambda function does thing differently. It constructs an object of class C as to per defined effect of that expression.
You could use a bogus argument and SFINAE
template <class F, class... Args>
auto apply ( F&& f, Args&&... args)
-> std::enable_if_t<std::is_invocable<F, Args...>::value,
typename std::result_of<F(Args...)>::type>
{
return f(args...);
}
template <class T, class... Args>
auto apply ( T&&, Args&&... args)
-> std::enable_if_t<!std::is_invocable<T, Args...>::value,T&&>
{
return std::move(T(args...));
}
but it's preferable to avoid that and rethink whatever meta-programming pattern you have in mind, i.e. avoid attempt to call same template name for different kinds of arguments, or make amends with lambda use. E.g. you may avoid to call apply() by using SFINAE.

std::bind and perfect forwarding

The following code does not compile:
#include <functional>
template<class ...Args>
void invoke(Args&&... args)
{
}
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<Args...>, std::forward<Args>(args)...);
binder();
}
int main()
{
int a = 1;
bind_and_forward(a, 2);
}
If I understand correctly, the reason is as follows: std::bind copies its arguments, and when the binder's operator() is called, it passes all the bound arguments as lvalues - even those ones that entered bind as rvalues. But invoke was instantiated for the original arguments, and it can't accept what the binder attempts to pass it.
Is there any solution for this problem?
Your understanding is correct - bind copies its arguments. So you have to provide the correct overload of invoke() that would be called on the lvalues:
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<Args&...>, std::forward<Args>(args)...);
^^^^^^^^
binder();
}
This works on most types. There are a few exceptions enumerated in [func.bind.bind] for operator(), where Arg& is insufficient. One such, as you point out, is std::reference_wrapper<T>. We can get around that by replacing the Args&usage above with a type trait. Typically, we'd just add an lvalue reference, but for reference_wrapper<T>, we just want T&:
template <typename Arg>
struct invoke_type
: std::add_lvalue_reference<Arg> { };
template <typename T>
struct invoke_type<std::reference_wrapper<T>> {
using type = T&;
};
template <typename T>
using invoke_type_t = typename invoke_type<T>::type;
Plug that back into the original solution, and we get something that works for reference_wrapper too:
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<invoke_type_t<Args>...>,
// ^^^^^^^^^^^^^^^^^^^
std::forward<Args>(args)...);
binder();
}
Of course, if one of Arg is a placeholder this won't work anyway. And if it's a bind expression, you'll have to write something else too.

C++ universal function caller

I'd want to implement a function caller that works just like the thread constructor. For example
std::thread second (bar,0);
will start a thread which calls bar with the single argument 0. I would like to do the same thing, but I do not know how.
For example, given:
void myFunc(int a){
cout << a << endl;
}
I would like:
int main() {
caller(myFunc,12);
}
to call myFunc with the parameter 12.
std::bind will make a callable object from any callable object with an arbitrary set of parameters, just as the thread constructor does. So just wrap that in a function that calls it:
template <typename... Args>
auto caller(Args &&... args) {
return std::bind(std::forward<Args>(args)...)();
}
Note that the auto return type requires C++14 or later. For C++11, you'll have to either return void, or specify the type:
auto caller(Args &&... args)
-> decltype(std::bind(std::forward<Args>(args)...)())
If all you want to do is call an arbitrary function with an arbitrary argument, that's just a template on both types:
template <typename Function, typename Arg>
void call_with_one(Function&& f, Arg&& arg) {
f(std::forward<Arg>(arg));
}
which you can expand to call with any number of args by making it variadic:
template <typename Function, typename... Arg>
void call_with_any(Function f, Arg&&... args) {
f(std::forward<Arg>(args)...);
}
Or really f should be a forwarding reference as well:
template <typename Function, typename... Arg>
void call_with_any(Function&& f, Arg&&... args) {
std::forward<Function>(f)(std::forward<Arg>(args)...);
}
Note that this will only work with functions and objects that implement operator(). If f is a pointer-to-member, this will fail - you will have to instead use std::bind as Mike Seymour suggests.

How to create a variadic template function with `std::function` as a function parameter?

How can I create a variadic template function with std::function as a function parameter that accepts a variadic number of arguments? I tried to reduce the problem to a MWE:
#include <functional>
template <class T> void run(std::function<void(T *)> fun, T *obj) { fun(obj); }
template <class T, class... Args>
void run_variadic(std::function<void(T *, Args...)> fun, T *obj, Args... args) {
fun(obj, args...);
}
struct Foo {
void bar() {}
};
int main() {
Foo foo;
std::function<void(Foo *)> fun = &Foo::bar;
run(fun, &foo); // works
run<Foo>(&Foo::bar, &foo); // works
run_variadic(fun, &foo); // works
run_variadic<Foo>(&Foo::bar, &foo); // does not compile
}
It seems like the mere presence of the variadic template parameter in run_variadic makes it impossible to directly call it with a member function pointer. clang's error message is as follows:
main.cpp:21:3: error: no matching function for call to 'run_variadic'
run_variadic<Foo>(&Foo::bar, &foo); // does not compile
^~~~~~~~~~~~~~~~~
main.cpp:6:6: note: candidate template ignored: could not match 'function<void (Foo *, type-parameter-0-1...)>' against 'void (Foo::*)()'
void run_variadic(std::function<void(T *, Args...)> fun, T *obj, Args&&... args) {
^
1 error generated.
Any suggestions on how I can fix run_variadic so that I do not have to go through the extra std::function object?
Background
I have a class hierarchy as
template <class T> class Abstract { ... };
class UnrelatedStuff { ... };
class Derived : public Abstract<UnrelatedStuff> { ... };
There are multiple Derived classes that all have to implement one or more methods to loop over a range of elements. The loop looks something like
#pragma omp parallel for
for (ZFSId i = begin; i != end; ++i) {
callMemFun(i, and, other, args);
}
All loops should be OpenMP-accelerated. I want the accelerator stuff factored out and not repeated in each method of Derived that uses a loop, so that I only have to change one place if e.g. OpenMP would switch to OpenACC.
Thus I am looking for a way to put the loop (and its decoration) in its own function. Moving it to the Abstract base class is not an option either, since the loops are performance-critical and I cannot have an abstract function call in each loop iteration.
You are almost always certainly better off abstracting away the function object:
template <class Functor, class... Args>
void run(Functor&& f, Args&&... args) {
f(std::forward<Args>(args)...);
}
This allows you to do the right thing at call site:
// function object is a lambda that binds to a member function:
run([&](auto... args) { foo.bar(args...); } /*, bar takes no args...*/);
I prefer a lambda to std::function or std::bind but you can also use those if they are already available:
run(std::function<void(Foo *)>{&Foo::bar}, &foo);
run(std::bind(&Foo::bar, &foo));
run(std::mem_fn(&Foo::bar), foo);
I provide a full example program below.
You have now edited the question with new information regarding what you are trying to do.
I'm pretty sure that you don't want to do this, since the OpenMP/OpenACC pragmas like parallel for usually require extra annotations for delivering reasonable performance, and they depend on what you are exactly trying to do at call site.
Still, if you really really want to go this route you can write your own for_each algorithm and dispatch according to an ExecutionAgent (see N3874 and N3731). If OpenMP, TBB, OpenACC parallel task are too slow, you can also easily provide overloads based on e.g. an ExecutionPolicy like this:
template<class RandomAccessRange, class Functor,
class ExecutionPolicy = execution::serial_t>
void for_each(RandomAccessRange&& r, Functor&& f,
ExecutionPolicy&& ex = ExecutionPolicy{}) {
detail::for_each_(std::forward<RandomAccessRange>(r),
std::forward<Functor>(f),
std::forward<ExecutionPolicy>(ex));
}
And then you can implement overloads of for_each_ for each execution policy, e.g.:
namespace detail {
template<class RandomAccessRange, class Functor>
void for_each(RandomAccessRange&& r, Functor&& f, execution::serial_t) {
boost::for_each(std::forward<RandomAccessRange>(r), std::forward<Functor>(f));
}
template<class RandomAccessRange, class Functor>
void for_each(RandomAccessRange&& r, Functor&& f, execution::openmp_t) {
#pragma omp parallel for
for (auto&& v : r) { f(v); }
}
template<class RandomAccessRange, class Functor>
void for_each(RandomAccessRange&& r, Functor&& f, execution::openacc_t) {
#pragma acc parallel for
for (auto&& v : r) { f(v); }
}
template<class RandomAccessRange, class Functor>
void for_each(RandomAccessRange&& r, Functor&& f, execution::tbb_t) {
tbb::parallel_for_each(std::begin(std::forward<RandomAccessRange>(r)),
std::end(std::forward<RandomAccessRange>(r)),
std::forward<Functor>(f));
}
} // namespace detail
Note that the ExecutionPolicy is just a tag, i.e.:
namespace execution {
struct serial_t {}; static const constexpr serial_t serial{};
struct openmp_t {}; static const constexpr openmp_t openmp{};
struct openacc_t {}; static const constexpr openacc_t openacc{};
struct tbb_t {}; static const constexpr tbb_t tbb{};
} // namespace execution
This will at least give you an efficient TBB backend even tho the OpenMP/OpenACC performance will be mediocre at best. You can take a look at the parallel implementation of libstdc++ where they use OpenMP. Their for_each algorithm is over 1000 lines of code and uses work-stealing.
Full example program:
#include <functional>
template <class Functor, class... Args>
void run(Functor&& f, Args&&... args) {
f(std::forward<Args>(args)...);
}
struct Foo { void bar() {} };
int main() {
Foo foo;
run([&](auto... args) { foo.bar(args...); } /*, bar takes no args*/);
run(std::function<void(Foo *)>{ &Foo::bar}, &foo);
run(std::bind(&Foo::bar, &foo));
run(std::mem_fn(&Foo::bar), foo);
}
To answer your comment on the previous answer, that answer can be adapted to support pointers to member functions in the way that you've asked for. The previous answer already works for all callable objects, but not directly with a pointer to member function because those are not callable with the usual f(args) syntax. The following version uses tag dispatch to distinguish between pointers to member functions and traditional callable objects, applying the call syntax appropriate to each case.
template <class Functor, class... Args>
void run_helper(std::false_type, Functor f, Args&&... args)
{
f(std::forward<Args>(args)...);
}
template <class Functor, class Arg0, class... Args>
void run_helper(std::true_type, Functor f, Arg0&& arg0, Args&&... args)
{
(std::forward<Arg0>(arg0).*f)(std::forward<Args>(args)...);
}
template <class Functor, class... Args>
void run(Functor f, Args&&... args)
{
run_helper(typename std::is_member_pointer<Functor>::type(),
f, std::forward<Args>(args)...);
}
This can be used in all the same ways as the previous answer could, but also supports directly passing in a pointer to member function:
run(&Foo::bar, foo);
It even works with overloaded member functions and member functions which are templates, if you explicitly instantiate the run template to bind to a particular overloaded function or function template instantiation.
Live example: http://ideone.com/vsBS4H

binding member functions in a variadic fashion

I have a member function with a variable number of parameters, stored in a std::function, and I want to bind the instance and get an independent function object.
template <class T, class R, class... Args>
void connect(const T& t, std::function<R(const T&, Args...)> f) {
std::function<R(Args...)> = /* bind the instance c into the function? */
}
// ...
Class c;
connect(c, &Class::foo);
For a fixed number of arguments I'd use std::bind, but I don't see how to do this for variadic parameters.
I hope this is what you were trying to achieve:
#include <iostream>
#include <cstdarg>
#include <functional>
class Class {
public:
void foo(...)
{
std::cout << "foo" << std::endl;
}
};
template <typename RES_T>
using ClassVarMemFunT = RES_T (Class::*)(...);
// Without typedef:
// template <class... ARGS, class CLASS_T, class RES_T>
// std::function<RES_T(ARGS...)> connect(CLASS_T& object, RES_T (CLASS_T::*funPtr)(...))
template <typename... ARGS, typename CLASS_T, typename RES_T>
std::function<RES_T(ARGS...)> connect(CLASS_T& object, ClassVarMemFunT<RES_T> funPtr)
{
std::function<RES_T(ARGS...)> resultFun = [&object, funPtr](ARGS&&... args) -> RES_T {
return (object.*funPtr)(std::forward<ARGS>(args)...);
};
return resultFun;
}
int main() {
Class c;
auto funPtr1 = connect<int, float>(c, &Class::foo);
funPtr1(10, 2.f);
auto funPtr2 = connect<double, float, int>(c, &Class::foo);
funPtr2(2., 2.f, 10);
return 0;
}
In my implementation connect expects the actual argument types as template parameters. The connect function returns an std::function that expects arguments with ARGS... types.
connect has two parameters:
one for the object that has a variadic function (object).
one for the member function pointer that points to the variadic function we would like to call (funPtr).
We cannot use std::bind in the implementation (we could, but it would involve a lot of boilerplate to add as many std::placeholders as we need based on the ARGS).
So I introduce a lambda instead, that expects the actual ARGS typed arguments. We can return the lambda as an std::function and we are good to go.
https://godbolt.org/z/7cx3rcYh8
I created a version that can print out the variadic list as well:
https://godbolt.org/z/nMxj7Wh9j