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

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