C++11 template tricks: Finding the return value type for member function-pointer

[Shameless Plug Warning] :
You have until August 31st, 2017 to try out NetMon and participate in LogRhythm’s Network security contest. Win up to $18,000 when applying your scripting skills to detect network vulnerabilities.  See https://logrhythm.devpost.com/ for more information.

Using templates you can deduct the return type from a non-member function fairly easy.

#include <type_traits>
int foo(int i) {   return i;  }

int main() {
   static_assert(std::is_same<decltype(foo(123)), int>::value, "");
}

Finding the return type for a member function is a little trickier. You can do it in various ways. decltype can still be used but now we also need the power of std::result_of

#include <type_traits>
struct A
{
    int foo(int i) { return i; }
};

int main() {
   A a;
   auto func = &A::foo;

   static_assert(std::is_same<decltype(a.foo(123)),
	                      std::result_of<decltype(&A::foo)(A, int)>::type
	                      >::value, "");
}

When finding the return type for member-function pointers is useful

I find the above trick of using

std::result_of<decltype(&Class::Function)(Type, Args)>::type

very helpful when dealing with functions that return the value of the function that was given as a input argument. Examples here could be anything from basic template functions to thread pools and task execution.

Nonsense example: Execute the function and return the result.

 struct A {
    int foo(int i) { return i; }
    void bar(int i) { /*nothing */ }

    template<typename Func, typename... Args>
    auto call(Func func, Args&&... args) const
              ->  typename std::result_of< decltype(func)(A*, Args...)>::type {

   return this->*func(args...);
 }

int main() {
  A a;
  auto func = &A::foo;
  static_assert(std::is_same<decltype(a.foo(123)),
                             decltype(a.call(func, 123))>::value, "");
}

Example code can be found at coliru.

std::future<T> : task execution, getting the T

For thread pools or job task execution you a lot of times want to return a std::future<T> Getting that “T” can be done in a similar way.

// Simplified example from:
// https://github.com/KjellKod/concurrent/blob/master/src/concurrent.hpp
   template<typename Call, typename... Args>
   auto call(Call func, Args&&... args) const
     -> std::future<typename std::result_of< decltype(func)(T*, Args...)>::type> {

   typedef typename std::result_of<decltype(func)(T*, Args...)>::type result_type;
   typedef std::packaged_task<result_type()> task_type;

   // weak compiler support for expanding parameter pack in a lambda. std::function
   // is the work-around. With better compiler support it can be changed to
   // something similar to:
   //       auto bgCall = [&, args...]{ return (_worker.*func)(args...); };
   //
   auto bgCall = std::bind(func, _worker.get(), std::forward<Args>(args)...);
   task_type task(std::move(bgCall));
   std::future<result_type> result = task.get_future();

  /* put the task in a job queue for the
     thread(s) to execute */

   return result;
}

Real World Example

1. Wrap any object with concurrent to make access to it asynchronous. Reference: https://github.com/KjellKod/concurrent/blob/master/src/concurrent.hpp.

The same tech is used in G3log when calculating the return value from arbitrary sink functions that are executed in a background thread.

Advertisements

About kjellkod

Software Engineer by trade, (former?) Martial Artist and Champion by strong will and small skill... and a Swede by nationality :)
This entry was posted in C++, coding, concurrency, Uncategorized. Bookmark the permalink.

One Response to C++11 template tricks: Finding the return value type for member function-pointer

  1. Pingback: Concurrency : concurrent<T> (wrapper), part II | Kjellkod's Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s