Как передать практически все в функцию в C ++ (или C)? - PullRequest
4 голосов
/ 30 июля 2011

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

 void MyFunc( *pointer ); 

А затем используйте его как:

char * x = "YAY!";
MyFunc(x);

int y = 10;
MyFunc(&y);

MyObj *b = new MyObj();
MyFunc(b);

И я не хочу использовать шаблоны, потому что я в основном использую C в своем проекте. Есть ли что-нибудь , которое можно использовать здесь, кроме макроса функции?

Ответы [ 5 ]

11 голосов
/ 30 июля 2011

В C ++ Boost.Any позволит вам сделать это безопасным для типов способом:

void func(boost::any const &x)
{
    // any_cast a reference and it
    // will throw if x is not an int.
    int i = any_cast<int>(x);

    // any_cast a pointer and it will
    // return a null pointer if x is not an int.
    int const *p = any_cast<int>(&x);
}

// pass in whatever you want.
func(123);
func("123");

В C вы будете использовать указатель void:

void func(void const *x)
{
    // it's up to you to ensure x points to an int.  if
    // it's not, it might crash or it might silently appear
    // to work. nothing is checked for you!
    int i = *(int const*)x;
}

// pass in whatever you want.

int i = 123;
func(&i);

func("123");

Кажется, вы против этого, но я все равно рекомендую: если вы используете C ++, примите это.Не бойтесь шаблонов.Такие вещи, как Boost.Any и void указатели имеют место в C ++, но они очень малы.

Обновление :

Ну, я делаю небольшойсигналы - слоты - библиотека подключений для использования с моим набором инструментов GUI.Так что я могу избавиться от Гадкого WNDPROC.Мне нужны эти указатели для соединений.

Если вам нужны многоцелевые сигналы, Boost.Signals уже обеспечивает полную и проверенную реализацию сигналов / слотов.Вы можете использовать Boost.Bind (или std::bind, если у вас есть компилятор C ++ 0x) для подключения функций-членов:

struct button
{
    boost::signal<void(button&)> on_click;
}

struct my_window
{
    button b;

    my_window()
    {
        b.on_click.connect(std::bind(&my_window::handle_click,
                                     this, std::placeholders::_1));
    }

    void handle_click(button &b)
    {
    }

    void simulate_click()
    {
        b.on_click(b);
    }
};

Если вы хотите только простойобратный вызов, Boost.Function (или std::function, если у вас есть компилятор C ++ 0x) будет хорошо работать:

struct button
{
    std::function<void(button&)> on_click;
}

struct my_window
{
    button b;

    my_window()
    {
        b.on_click = std::bind(&my_window::handle_click,
                               this, std::placeholders::_1);
    }

    void handle_click(button &b)
    {
    }

    void simulate_click()
    {
        b.on_click(b);
    }
};
7 голосов
/ 30 июля 2011

Вы можете использовать функцию, которая принимает void*, но вы должны знать о типах указателей, которые не совместимы с void*:

  • указатели на функции:

    void MyFunc(void*);
    
    MyFunc(&MyFunc); // WRONG
    
  • указатели на участников:

    void MyFunc(void*);
    
    struct A { int x; };
    
    MyFunc(&A::x); // WRONG
    

Хотя эти указатели не совместимы с void* (даже с приведением в некоторых компиляторах), они сами являются данными. Таким образом, вы можете передать указатель на указатель:

void MyFunc(void*);

void (*pfn)(void*) = &MyFunc;
MyFunc(&pfn); // ok

struct A { int x; };
int A::*px = &A::x;
MyFunc(&px); // ok
2 голосов
/ 30 июля 2011

Вы можете определить метод как принимающий один void * аргумент. Конечно, в этот момент вы должны выяснить, что делать с данными (в том, что касается их доступа или приведения).

void MyFunc(void * ptr);
1 голос
/ 30 июля 2011

Вы можете использовать:

void MyFunc( void* p){}

int g = 10;
MyFunc( (void*)&g );
0 голосов
/ 30 июля 2011

void * это способ сделать это. Вы можете назначить любой тип указателя на void *. Но чтобы использовать указатель в вызываемой функции, вам нужно знать тип, чтобы вы могли создать соответствующий локальный указатель или преобразовать его соответствующим образом. Вы можете закодировать ограниченный набор типов как символы перечисления и, возможно, использовать переключатель для выбора поведения, специфичного для типа. Но без какой-либо конкретной цели или варианта использования вы можете в итоге гоняться за хвостом в поисках общности, для которой С никогда не предназначался.

Другим способом было бы создать объединение, содержащее все различные типы, которые, как вы знаете, необходимы .

typedef union {
    int i;
    char c;
    float f;
} vartype;

Тогда, если значение может содержать свой собственный идентификатор типа, оно становится объединением тегов или вариантом записи.

typedef struct {
    enum type { INT, CHAR, FLOAT } type;
    vartype var;
} varrec;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...