typedef'ing функция * signature * (не указатель на), чтобы ее можно было повторно использовать? - PullRequest
6 голосов
/ 04 марта 2011

РЕДАКТИРОВАТЬ: МОТИВАЦИЯ

Предположим, я определяю класс обработчика как

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

Клиент может сделать

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);
  // ....
}

Компилятор будетдействительно, проверьте, что f1 и f2 соответствуют параметрам registerCallback, однако клиент должен правильно определить f1 и f2.Поскольку я уже typedef ed Callback, я бы хотел, чтобы клиент мог использовать его вместо этого.

END EDIT

Я бы хотелхотел бы сделать что-то вроде этого:

typedef int arithmetic(int i, int j);

arithmetic sum
{
 return i+j;
}

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

Однако, оба

arithmetic sum
arithmetic sum()

не компилируются, а также этот

arithmetic sum(int i, int j)

, который дает ошибку компилятора

func.cpp: 4: ошибка: 'sum' объявлена ​​как функция, возвращающая функцию

Причина, по которой я хочу это, заключается в том, что я хочу получить Handlerкласс, обеспечивающий typedef для функции обратного вызова, которую он принимает, , включая список параметров .

Ответы [ 5 ]

12 голосов
/ 04 марта 2011

Я дам вам классический ответ C, не прибегая к новомодным игрушкам C ++ 0x. Давайте начнем с определения прототипа функции:

typedef int TWO_ARG_FUNC(int x, int y);

Вы можете использовать этот прототип при получении указателя на функцию, например ::10000

void blah(TWO_ARG_FUNC* funcPtr);

... или при объявлении функции вперед:

TWO_ARG_FUNC max;

... но вы не можете реализовать функцию, просто написав прототип, например ::

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

Однако не все потеряно. Вы можете принудительно заставить функцию оставаться верной для прототипа, сначала объявив его вперед:

TWO_ARG_FUNC max;

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

Другой вариант - использовать макросы C:

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

DEFINE_TWO_ARG_FUNC(max)
{
}

и вы даже можете использовать макрос для объявления прототипа функции, если позже вы захотите объявить указатель на такую ​​функцию:

typedef DEFINE_TWO_ARG_FUNC(TWO_ARG_FUNC);
9 голосов
/ 04 марта 2011

Во-первых, вы не набрали определение подписи. Подпись - это все, что идентифицирует одну функцию. Он содержит пространство имен / класс функции и так далее.

То, что вы напечатали, является типом функции. Например, когда вы typedef int inttype определяете тип int, вы определяете тип функции.

Вы можете использовать typedef-name только для объявления функций.

arithmetic max; // valid

Но его нельзя использовать для определения функций. Для определения функций необходимо предоставить список параметров буквально и вручную. Причины включают указание имен для параметров (и, возможно, другие, более технические причины. C ++ 0x вводит arithmetic max {};, который получит конкретное значение инициализации).

3 голосов
/ 04 марта 2011

Думая о вашем посте, я сделаю снимок того, что вы хотите заархивировать.Вы можете попробовать использовать boost или C ++ 0x lambda.Я пойду с наддувом.

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

Так что, возможно, это то, что вы хотите архивировать.

Это также возможно с полнофункциональной функцией.Вот, пожалуйста.

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

Это будет то же самое, что и sum1.Вы можете свободно использовать весь материал Boost Bind.Например, привязка к методу объекта или тому, что вы хотите.

2 голосов
/ 04 декабря 2014

Я не нашел решения с точным синтаксисом, который вы ищете, но что-то вроде этого работает:

#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;
}
2 голосов
/ 04 марта 2011

Поскольку, как вы говорите, вы можете использовать C ++ 0x, вы можете сделать что-то подобное, набрав function:

edit , добавленный вВаша концепция класса обработчика, содержащего обратный вызов 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;
}

Это не тот синтаксис, который вы ищете, но, как отмечали другие, невозможно использовать typedef дляподпись функции напрямую.

...