2

I have questions with below code snippet, not sure if I correctly understand the codes.

template <typename R, typename... Args>                                     
class RunnableAdapter<R(*)(Args...)> {
 public:
  typedef R (RunType)(Args...);

  explicit RunnableAdapter(R(*function)(Args...))   
      : function_(function) {
  }

  R Run(Arg... args) {
    return function_(args...);
  }

 private:
  R (*function_)(Args...);
};
  1. <R(*)(Args...)> is a "type of function pointer"and blink space between R and (*) is not necessarily required?

  2. and what could instanciation of RunnableAdapter be? I assume it is like below.
    void myFunction(int i){ // }; RunnableAdfapter<(void)(*)(int)> ra(MyFunction); ra.Run(1); //which calls MyFunction(1)

Eunice
  • 137
  • 1
  • 6

1 Answers1

1

At first the code you provided have some mistakes and does not even compile. To answer tou questions:

  1. Spaces are not necessary.
  2. See below example

You could declare you class like this

template <typename T>
class RunnableAdapter;

template <typename R, typename... Args>                                     
class RunnableAdapter<R(*)(Args...)> { ... }

And instantiate it

RunnableAdapter<void(*)(int)> ra(&myFunction);

But you could simplify it (here is full working example)

#include <iostream>
#include <string>

template <typename T>
class RunnableAdapter;

template <typename R, typename... Args>                                     
class RunnableAdapter<R (Args...)> {
public:

  explicit RunnableAdapter(R(*function)(Args...))   
      : function_(function) {
  }

  R Run(Args... args) {
    return function_(args...);
  }

private:
  R (*function_)(Args...);
};

void myFunction(int i){ std::cout << i << std::endl; }

int main()
{
    RunnableAdapter<void(int)> ra(&myFunction);
    ra.Run(1);
}

This would allow instantiation with signature-like expressions like void(int). It just looks better, no need in (*).

Also here is another way is to do it without class specialization, like this. The result is the same, but class declaration and instantiation is slightly different.

#include <iostream>
#include <string>

template <typename R, typename... Args>                                     
class RunnableAdapter {
public:

  explicit RunnableAdapter(R(*function)(Args...))   
      : function_(function) {
  }

  R Run(Args... args) {
    return function_(args...);
  }

private:
  R (*function_)(Args...);
};

void myFunction(int i){ std::cout << i << std::endl; }

int main()
{
    RunnableAdapter<void, int> ra(&myFunction);
    ra.Run(1);
}

EDIT

As @Jarod42 proposed it is better to make Run like this

template<typename... Ts>
R Run(Ts&&... args) {
  return function_(std::forward<Ts...>(args)...);
}
Nikolay K
  • 3,770
  • 3
  • 25
  • 37
  • Run should be written `template R Run(Ts&&... args) { return function_(std::forward(args)...); }` (to handle function which transfers `unique_ptr` ownership, for example). – Jarod42 Aug 12 '15 at 06:59
  • @Jarod42 does it need another template `template `? What is the difference from `R Run(Args&&... args) { return function_(std::forward(args)...); }`? However good comment, I will update my answer. – Nikolay K Aug 12 '15 at 07:08
  • With `Ts&&` you have forward reference (`Ts` is deduced from function call). `Args&&` are fixed by class and would be reference (r-value or l-value reference depending of `Args` and collapsing rules). – Jarod42 Aug 12 '15 at 07:17
  • Thanks! guys and sorry for not fully working code. I jsut tired to study part of open source. now it makes more sense to me. it is way better neat without (*) though, original source just has it. it made me more confused. and original code had wrapping code for function parameters as well. :) – Eunice Aug 13 '15 at 07:34
  • now I got understood why specialized `RunnableAdapter `is needed. since it should be differenctiated from `RunnableAdapter`. so have different RunType each for function and method binding. – Eunice Aug 13 '15 at 08:09