Question

I'm playing with functor composition, where the return type of a functor depends on the input type:

template<typename V>
class F
{
protected:
    V v_;
public:
    using return_type = ?;

    F(V v) : v_(v) {}

    template<typename T>
    typename T::U operator()(T t)
    {
        v.method(t);
    }
};

...

X x;
Y y;
F<X> f(x);
F<Y> g(y);
auto h = std::bind(f, std::bind(g, _1));
h(...);  // problem is here :(

Is it possible to find return_type using decltype so that std::bind will work? If so, how?

Edit: I replace U<T> with typename T::U because the return type depends on the type. I hope this is clearer now.

Edit 2 (4?): Added a compilable example that reproduces the problem.

#include <functional>

using namespace std::placeholders;

template<typename I>
struct R
{
    using IT = I;
    R(I x, I y) : b(x), e(y) {}
    I b;
    I e;
};

template<typename IN, typename II>
class CI
{
    CI(II i) {}
};

template<typename IN>
class C
{
    template<typename IR>
    R<CI<IN, typename IR::IT> >
    operator()(IR& i)
    {
        return R<CI<IN, typename IR::IT> >(
            CI<IN, typename IR::IT>(i.b),
            CI<IN, typename IR::IT>(i.e));
    }
};

struct F {};
struct G {};
struct H {};

int main(int argc, char* argv[])
{
    C<F> a;
    C<G> b;
    auto c = std::bind(a, std::bind(b, _1));
    R<H> r{H{}, H{}};
    c(r);
}
Was it helpful?

Solution

Forget about using std::bind for a minute and just try the direct approach:

C<F> a;
C<G> b;
R<H> r{H{}, H{}};
a(b(r));

This won't even compile, so there's no way the bind version will!

b(r) isn't valid because of an access violation, and if you fix that a(b(r)) fails because you try to bind a temporary to a non-const lvalue-reference

OTHER TIPS

Solved it! I had to replace C::operator()(IR& i) with C::operator()(IR i) because it was recursive. Maybe adding a move constructor to IR would help performance, but...? In fact, what happened was that clang's errors weren't as helpful as gcc's. Well, blame me.

Your example can be solved using alternative function syntax:

#include <iostream>
#include <functional>

template<typename T>
struct Number {
  T t_;
  Number(T t) : t_(t) {}
  T operator+(T t) { return t_ + t; }
};

struct F {
  template<typename T>
  auto operator()(T x) -> decltype(x + 1)
  {
    return x + 1;
  }
} f, g;

int main(int argc, char* argv[])
{
  using namespace std::placeholders;
  auto h = std::bind(f, std::bind(g, _1));
  std::cout << h(Number<int>(1)) << std::endl;
}

and value_type is not needed here and it fact it provided problems as int returned from g(_1) will never have int::value_type inside expected by f.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top