Reputation: 1674
I'm trying to make a helper function that executes a lambda/std::function when called if the given weak_ptr is valid. Currently the following code works, but unfortunately, it requires me to define the template parameters. I'm looking for a way to do this with automatic template argument deduction.
template <typename DependentType, typename... ArgumentTypes>
auto make_dependent(std::weak_ptr<DependentType>& dependent, std::function < void(ArgumentTypes...)> functor) -> decltype(functor)
{
return [&dependent, functor] (ArgumentTypes... args)
{
if (!dependent.expired()) {
functor(args...);
}
};
};
Ideally, I would like to replace the std::function <void(ArgumentTypes...)>
with a generic template parameter FunctorType
, but then I'm not sure how I would extract arguments from FunctorType
. The above code works, the below code is theoretical:
template <typename DependentType, typename FunctorType>
auto make_dependent_ideal(std::weak_ptr<DependentType>& dependent, FunctorType functor) -> decltype(std::function<return_value(functor)(argument_list(functor))>)
{
return[&dependent, functor](argument_list(functor) args)
{
if (!dependent.expired()) {
functor(args...);
}
}
}
Is there any way to do something like this?
Upvotes: 8
Views: 1446
Reputation: 14158
Here's how I'd solve your problem in C++14:
template<typename DependentType, typename FunctorType>
auto make_dependent(std::weak_ptr<DependentType> &dependent, FunctorType functor) {
return [&dependent, functor](auto &&...args) {
if (!dependent.expired())
functor(std::forward<decltype(args)>(args)...);
}
}
I'm using two C++14 features here:
make_dependent
functor
EDIT: The code above captures dependent
by reference, as your original code did. Is that really what you want?
Upvotes: 2
Reputation: 15524
You can use a proxy trait class to extract the return type and arguments separately from a single template parameter. The Trait
class uses the static function dependent_func
to create the lambda you want to return.
template <typename DependentType, typename FunctorType>
struct Trait {};
template <typename DependentType, typename ReturnType, typename... ArgumentTypes>
struct Trait<DependentType, std::function<ReturnType(ArgumentTypes...)>> {
static std::function<ReturnType(ArgumentTypes...)> dependent_func(const std::weak_ptr<DependentType>& dependent, std::function<ReturnType(ArgumentTypes...)>& functor) {
return [&dependent, &functor] (ArgumentTypes... args) {
if (!dependent.expired()) {
return functor(args...);
}
};
}
};
template <typename DependentType, typename FunctorType>
auto make_dependent_ideal(std::weak_ptr<DependentType>& dependent, FunctorType& functor) -> decltype(Trait<DependentType, FunctorType>::dependent_func(dependent, functor)) {
return Trait<DependentType, FunctorType>::dependent_func(dependent, functor);
}
For more info about parsing template arguments in this way, look at this question: C++ parsing function-type template argument
Upvotes: 1
Reputation: 275310
The easiest way to solve your problem with extracting arguments from your parameter is to not extract the arguments from your parameter.
template<typename F, typename C>
struct conditional_forwarder {
F func;
C cond;
template<typename Fin, typename Cin>
conditional_forwarder( Fin&& f, Cin&& c ):
func(std::forward<Fin>(f)), cond(std::forward<Cin>(c)) {}
template<typename... Args>
void operator()( Args&&... args ) const {
if (cond())
func( std::forward<Args>(args)... );
}
};
template<typename F, typename C>
conditional_forwarder< typename std::decay<F>::type, typename std::decay<C>::type >
make_conditional_forwarder( F&& f, C&& c ) {
return {std::forward<F>(f), std::forward<C>(c)};
}
// todo: make_dependent_test
template <typename DependentType, typename FunctorType>
auto make_dependent_ideal(std::weak_ptr<DependentType>& dependent, FunctorType functor)
-> decltype(make_conditional_forwarder( make_dependent_test(dependent), functor) )
{
return make_conditional_forwarder( make_dependent_test(dependent), functor);
}
much of this will be easier in C++14.
As an aside, there seems to be a fundamental design flaw: the conditional forwarder should probably aquire a .lock()
on the weak_ptr
, and then execute functor
within that lock, so that the precondition (that the resource is held) holds for the entire call of functor
.
I'm also unsure why you are holding a reference to a weak_ptr
, when the remote state of a weak_ptr
can be copied.
In C++14, you can return something like:
return [=](auto&&... args) mutable {
}
I believe, and the decltype
stuff also goes away mostly as functions can deduce their return type more easily.
Upvotes: 5