(following on from C++ Guru Question)
There are a few reasons why the code before didn’t work: mainly
a) C++ template argument deduction works one-way with a list of candidates, it’s not H-M type inference.
b) A C++ lambda is a thing with some internal type, not a std::function (although it can be assigned to one, that doesn’t matter for template type deduction).
Anyway, a reasonable solution to this problem is to simplify the template argument matching to the function type, and use a simple function_traits template to take apart the function argument and return types.
template <typename T> struct function_traits : public function_traits<decltype(&T::operator())> {}; template <typename R, typename A> struct function_traits<R(A)> { typedef R returnType; typedef A argType; }; template <typename C, typename R, typename A> struct function_traits<R(C::*)(A) const> : public function_traits<R(A)> {}; template <typename T> struct Foo { T m_t; }; template <typename F> typename function_traits<F>::returnType operator/=( Foo<typename function_traits<F>::argType> foo, const F& fn) { return fn(foo.m_t); } void mystery() { auto foo = Foo<int>{1}; // this works... function<Foo<int>(int)> f1 = [] (int i) { return Foo<int>{i}; }; auto bar1 = foo /= f1; // this does too! auto f2 = [] (int i) { return Foo<int>{i}; }; auto bar2 = foo /= f2; } |