質問

Suppose I want to have a function double adapter(double), is there a general way to compose it with a boost::function<double(...)> functor to produce another boost::function<double(...)> functor2 where functor2(...) == adapter(functor(...))? In particular, it would be cool if there was a way to do this without using C++11.

edit To clarify, I'm interested in knowing if there's a way to write something that can handle any boost::function<double(...)>, i.e. ones that have different length signatures without having to copy and paste multiple times for 1, 2, 3, etc. arguments.

役に立ちましたか?

解決

Without c++11, there are a significant number of complexities, including the varadic arguments and forwarding.

With C++11, it can be done, mostly by specializaing std::is_bind_expression. When this function object is used in a bind, it calls the function object that was stored with all of the arguments that were provided during the call to the bound function object. Note, this works with any function object, not just std::function.

This works with GCC 4.7.

#include <functional>
#include <utility>
#include <type_traits>

namespace detail
{
template<typename Func>
struct compose_functor
{

   Func f;

   explicit compose_functor(const Func& f) : f(f) {};

   template<typename... Args>
   auto operator()(Args&&... args) const -> decltype(f(std::forward<Args>(args)...))
   {
    return f(std::forward<Args>(args)...);
   }

};

}

template<typename Func>
 detail::compose_functor
<Func> compose(Func f)
{
   return detail::compose_functor<Func>(f);
}


namespace std
{
   template<typename T>
   struct is_bind_expression< detail::compose_functor<T> > : true_type {};
}
#include <numeric>

int adapter(double d)
{
    return (int)d;
}

int main()
{
    std::function<int(double)> f1 = std::bind(adapter, compose(std::negate<double>()));
    std::function<int(double, double)> f2 = std::bind(adapter, compose(std::plus<double>()));

    // 1.5 -> -1.5 -> -1
    std::cout << f1(1.5) << std::endl;
    // 2.3+4.5 = 6.8 -> 6
    std::cout << f2(2.3, 4.5) << std::endl;
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top