Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deduce the return type of a std::bind object for template use?

I have a class which basically just manages a vector of custom types. To relieve me from writing the same iteration loop over and over again I wrote the following construct:

template<typename T>
uint64_t ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
{
  return std::accumulate(vec.begin(), vec.end(), 0, [&](uint64_t acc, const MyClass* c)
  {
    return acc + (c ? method(c) : 0);
  });
}

which is then called like this:

ACCUMULATE_ON_VECTOR(_myVec, std::bind(&MyClass::someMethod, std::placeholders::_1));

This works very well in concept but since I have a lot of methods returning different integer types (signed/unsigned, signed/unsigned long), I'd like to abstract away the for now hardcoded uint64_t cause I get compiler warnings all over the place. For this I somehow need to get the return type of the bind object. Can I somehow do this with decltype? What I'm looking for is this:

template<typename T>
<new deduced type> ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> vec, T method)
{
  return std::accumulate(vec.begin(), vec.end(), 0, [&](<new deduced type> acc, const MyClass* c)
  {
    return acc + (c ? method(c) : 0);
  });
}
like image 607
user1709708 Avatar asked Mar 13 '23 04:03

user1709708


1 Answers

You can do this using std::result_of:

template<typename Func>
typename std::result_of<Func(MyClass*)>::type
ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> &vec, Func method)
{
  using ResultType = typename std::result_of<Func(MyClass*)>::type;
  return std::accumulate(vec.begin(), vec.end(), ResultType{},
                         [&](typename std::result_of<Func(MyClass*)>::type acc,
                             const MyClass* c)
  {
    return acc + (c ? method(c) : ResultType{});
  });
}

Note I'm value-initializing the return type instead of using the integer literal zero.

It might be more readable to wrap the function parameter in a std::function<ResultT(MyClass*)>: the accumulate function would be directly templated on the result type, pushing responsibility for that up to the call site.


BTW, you don't need the auto/trailing return type technique here, because the return type doesn't depend on the argument list, only on the template parameter - nevertheless, I think it looks slightly nicer:

template<typename Func>
auto ACCUMULATE_ON_VECTOR(const std::vector<MyClass*> &vec,
                          Func method)
-> typename std::result_of<Func(MyClass*)>::type
{
like image 120
Useless Avatar answered Apr 29 '23 16:04

Useless