typedef'ing function *signature* (not a pointer to), so that it can be reused?

蓝咒 提交于 2019-12-06 00:56:09

问题


EDIT: MOTIVATION

Suppose I define a Handler class as

class Handler {
public:
  class Message { /*...*/ };
  typedef int (*Callback)(Message *msg);
  void registerCallback(int msgclass, Callback f);
};

A client can do

int f1(Handler::Message *msg)
{ /* handle message */ }

int f2(Handler::Message *msg)
{ /* handle message */ }

int main(){
  Handler h;
  h.registerCallback(1, f1);
  h.registerCallback(2, f2);
  // ....
}

The compiler will indeed check that f1 and f2 are appropriate as parameters to registerCallback, however, it's up to the client to define f1 and f2 correctly. Since I've allready typedefed Callback, I'd like the client to be able to use it instead.

END EDIT

I'd like to do something like this:

typedef int arithmetic(int i, int j);

arithmetic sum
{
 return i+j;
}

arithmetic max
{
  return (i>j)? i:j;
}
// etc.

However, both

arithmetic sum
arithmetic sum()

don't compile, and also this

arithmetic sum(int i, int j)

which gives compiler error of

func.cpp:4: error: ‘sum’ declared as function returning a function

The reason I want this is that I want to have a Handler class which would provide a typedef for a callback function it accepts, including the parameter list.


回答1:


First, you did not typedef a signature. A signature is everything that identifies a single function. It contains the namespace/class of the function and so on.

What you typedef'ed is the type of a function. Like when you typedef int inttype which typedefs the type of an int, you typedef'ed the type of a function.

You can use the typedef-name to declare functions only.

arithmetic max; // valid

But it cannot be used to define functions. For defining functions, you need to provide a parameter list literally and manually. Reasons include giving names for parameters (and possibly other, more technical reasons. C++0x introduces arithmetic max {}; which will get a specific initialization meaning).




回答2:


I'll give you a classic C answer, without resorting to the newfangled C++0x toys. Let's start by defining a function prototype:

typedef int TWO_ARG_FUNC(int x, int y);

You can use this prototype when receiving a function pointer, e.g.:

void blah(TWO_ARG_FUNC* funcPtr);

... or when forward-declaring a function:

TWO_ARG_FUNC max;

... but you cannot implement a function by just writing the prototype, e.g.:

TWO_ARG_FUNC max
{
   ... // bzzt, error!
}

However, not all is lost. You can enforce the function to remain true to a prototype by first forward-declaring it:

TWO_ARG_FUNC max;

int max(int a, int b)
{
    ...
}

Another option would be to resort to C macros:

#define DEFINE_TWO_ARG_FUNC(funcName) int funcName(int a, int b)

DEFINE_TWO_ARG_FUNC(max)
{
}

and you can even use the macro to declare a function prototype, in case you later want to declare a pointer to such a function:

typedef DEFINE_TWO_ARG_FUNC(TWO_ARG_FUNC);



回答3:


Thinking about your post I will give it a shot about what you want to archive. You could try using boost or C++0x lambda. I will go with boost.

typedef boost::function<int(int,int)> arithmetic;
arithmetic sum = (boost::lambda::_1 + boost::lambda::_2);
arithmetic max = boost::lambda::if_then_else_return(boost::lambda::_1 > boost::lambda::_2,
    boost::lambda::_1, boost::lambda::_2);

int j = sum(3,3); // j ist 6
int k = max(4,2); // k is 4

So maybe this is what you want to archive.

It is also possible with a full blown function. Here you go.

int FullBodyFunction(int i, int j)
{
    return i+j;
}
arithmetic sum2 = boost::bind(&FullBodyFunction, _1, _2);

This will do the same as sum1. You are free to use the whole boost bind stuff. E.g. bind to method of a object or what ever you want.




回答4:


Since, as you say, you can use C++0x, you might choose to do something like this by typedef'ing a function:

edit, added in your concept of a handler class containing a callback typedef:

#include <functional>
#include <list>

int max(int a, int b)
{
    return (a>=b) ? a : b;
}

class Handler
{
    public:

        //typedef int (*Callback)(int, int);
        typedef std::function<int (int, int)> Callback;

        void add(Callback func) { functions_.push_back(func); }

    private:

        std::list<Callback> functions_;
};

int main(int argc, char* argv[])
{
    Handler handler;

    handler.add([](int a, int b) -> int { return (a>=b) ? a : b; });
    handler.add(max);

    return 0;
}

This isn't the exact syntax you're looking for, but as others have pointed out, it isn't possible to use typedef for a function signature directly.




回答5:


I haven't find solution with exact syntax you are looking for, but something like this works:

#include <cassert>

#define  arithmetic (int i, int j) -> int

#define declare(Func, Name) auto Name Func

#define as_

auto sum as_ arithmetic
{
  return i + j;
};

declare(arithmetic, max)
{
  return (i>j) ? i : j;
};

int main()
{
  assert(sum(2, 4) == 6);
  assert(max(2, 4) == 4);

  return 0;
}


来源:https://stackoverflow.com/questions/5195269/typedefing-function-signature-not-a-pointer-to-so-that-it-can-be-reused

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!