I'm trying to use boost::binary_traits
to get the type of a functor's argument. It works for std::function
but not for "lambda types".
#include <boost/functional.hpp>
template<typename Functor>
void foo(Functor&& f)
{
boost::binary_traits<Functor>::first_argument_type a = 1; // error C2528: 'abstract declarator': pointer to reference is illegal
}
void bar()
{
auto func1 = [](int i, int j) { return j; };
std::function<int(int, int)> func2 = [](int i, int j) { return j; };
foo(func1);
boost::binary_traits<decltype(func1)>::first_argument_type b = 1; // error C2039: 'result_type': is not a member of 'bar::<lambda_227a80eb4d5d25e23ac8db99e4a9edf0>
boost::binary_traits<decltype(func2)>::first_argument_type c = 1; // OK
boost::binary_traits<std::function<int(int, int)>>::first_argument_type d = 1; // OK
}
How can I write foo
so that the foo(func1)
call works?
For context, this is what I'm trying to accomplish. Ideally without putting a bunch of helper templates alongside it in the header so that they're visible to the caller.
template<typename Iterable, typename Functor>
inline auto accumulate(Iterable& input, Functor&& accumulator)
{
boost::binary_traits<Functor>::first_argument_type output;
std::for_each(
std::begin(input),
std::end(input),
[&output, &accumulator](auto& m) { output = accumulator(output, m); });
return output;
}
According to the boost docs:
binary_traits
should be instantiated with either a function taking two parameters, or an adaptable binary function object (i.e., a class derived fromstd::binary_function
or one which provides the same typedefs). (See §20.3.1 in the C++ Standard.
A lambda doesn't meet either of those criteria, so it is not surprising that it doesn't work as-is. You will likely need to change your function to take a std::function
(or applying a concept to enforce the boost::binary_traits
requirements) instead of an arbitrary callable.
You could also use the deduction guides for std::function
to your advantage:
template<typename Functor>
void foo(Functor&& f)
{
typename decltype(std::function(f))::first_argument_type a = 1;
}