Given a pointer to a function object:
std::shared_ptr<std::function<double(double)>> f;
is there a built-in construct in C++11 that allows be to use this pointer in a std::bind
statement? For example:
std::function<double()> g = std::bind(built_in(f), 0.0);
What I am doing is to use variadic template as:
template<typename Ret, typename... Args>
std::function<Ret(Args...)> get_fn(const std::shared_ptr<std::function<Ret(Args...)>>& f)
{
return [=](Args... args) -> Ret { return (*f)(args...); };
}
This allows me to write:
std::function<double()> g = std::bind(get_fn(f), 0.0);
Thanks in advance.
Edit: I should have been clearer. I need to use the instance of the function object inside the shared pointer for optimization purposes.
If we had a Standard function object for the dereference operator (much like std::plus<T>
is for adding T
with T
) then we could involve a nested bind expression, but that is not the case -- plus we'd need a call operator because the usual substitutions that take place during the evaluation of nested bind expressions don't apply to the first argument! Your solution introduces an additional std::function
, so I'm proposing some alternatives that don't.
Write your own call and dereference operators:
struct call {
template<typename Callable, typename... Args>
auto operator()(Callable&& callable, Args&&... args) const
// don't use std::result_of
-> decltype( std::declval<Callable>()(std::declval<Args>()...) )
{ return std::forward<Callable>(callable)(std::forward<Args>(args)...); }
};
struct dereference {
template<typename T>
auto operator()(T&& t) const
-> decltype( *std::declval<T>() )
{ return *std::forward<T>(t); }
};
template<typename IndirectCallable, typename... Args>
auto indirect_bind(IndirectCallable&& f, Args&&... args)
-> decltype( std::bind(call {}
, std::bind(dereference {}, std::declval<IndirectCallable>())
, std::declval<Args>()... ) )
{ return std::bind(call {}
, std::bind(dereference {}, std::forward<IndirectCallable>(f))
, std::forward<Args>()... ); }
You can then do auto g = indirect_bind(f, 0.0);
. Here's a proof-of-concept that also shows how placeholders are appropriately dealt with.
I mention the above solution because functors like call
and dereference
are useful bricks -- I personally have them among my tools. My preferred solution however would be to write a polymorphic functor that does the indirection and call in one go:
template<typename Indirect>
struct indirect_callable_type {
// Encapsulation left as an exercise
Indirect f;
template<typename... Args>
auto operator()(Args&&... args)
// don't use std::result_of
-> decltype( std::declval<Indirect&>()(std::declval<Args>()...) )
{ return f(std::forward<Args>(args)...); }
template<typename... Args>
auto operator()(Args&&... args) const
// don't use std::result_of
-> decltype( std::declval<Indirect const&>()(std::declval<Args>()...) )
{ return f(std::forward<Args>(args)...); }
// Lvalue and rvalue *this version also left as an exercise
};
template<typename T>
indirect_callable_type<typename std::decay<T>::type>
make_indirect_callable(T&& t)
{ return { std::forward<T>(t) }; }
which you can, in fact, use as auto g = std::bind(make_indirect_callable(f), 0.0);
.
I should mention that unlike your solution, those requires writing some types out-of-line. This is an unfortunate situation due to the inherent limitations of lambda expressions. Should you wish to stick with what you currently have, I have a minor recommendation that inside the lambda you std::forward<Args>(args)...
the parameters. This might prove useful if you ever deal with move-only types.
There's a nice little hack you can use here, which is that INVOKE
on a pointer to member function automatically indirects its object argument when passed a pointer or (even) a smart pointer (20.8.2p1 second bullet, definition of INVOKE
):
#include <functional>
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<std::function<double(double)>> f
= std::make_shared<std::function<double(double)>>(
[](double d) { return d + 10.0; });
std::function<double()> g = std::bind(
&std::function<double(double)>::operator(), f, 0.0);
std::cout << g() << std::endl;
}
If you don't want to mention explicitly the type of f
:
std::function<double()> g = std::bind(
&std::remove_reference<decltype(*f)>::type::operator(), f, 0.0);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With