Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template argument deduction for lambdas

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?

like image 428
Axiverse Avatar asked Jul 30 '13 21:07

Axiverse


1 Answers

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.

like image 162
Yakk - Adam Nevraumont Avatar answered Oct 04 '22 19:10

Yakk - Adam Nevraumont