Переменные лямбда-выражения c ++ в классах

0

Я хочу сохранить переменные лямбда-выражения (например, в блоке кода кулака). Проблема в том, что тогда я использую классы (например, второй блок кода), компилятор возвращает мне некоторые ошибки. Я не знаю, как это исправить.

Надеюсь, кто-то может мне помочь и объяснить, почему он не работает так. Благодарю.

Первый код:

// variable for function pointer
void (*func)(int);
// default output function
void my_default(int x) {
    cout << "x =" << "\t" << x << endl << endl;
}


int main() {
    cout << "Test Programm\n\n";

    // 1. Test - default output function
    cout << "my_default\n";
    func = &my_default;
    func(5);

    // 2. Test - special output function 2
    cout << "my_func2\n";
    func = [](int x) {  cout << "x =" << "  " << x << endl << endl; };
    func(5);

    return 0;
}

Второй код:

class test {
private:
    // variable for function pointer
    void (*func)(int);
    // default output function
    void my_default(int x) {
        cout << "x =" << "\t" << x << endl << endl;
    }

public:
    void dummy(void) {
        // 1. Test - default output function
        cout << "my_default\n";
        func = &my_default;
        func(5);

        // 2. Test - special output function 2
        cout << "my_func2\n";
        func =  [](int x)->int{ cout << "x =" << "  " << x << endl << endl; };
        func(5);
    }
};


// entry
int main() {
    cout << "Test Programm\n\n";

    test a;
    a.dummy();

    return 0;
}

Составитель:

pi@raspberrypi ~/dev/property $ gcc -std=c++0x -o test2 test2.cpp -lstdc++
test2.cpp: In member function ‘void test::dummy():
test2.cpp:491:17: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&test::my_default [-fpermissive]
test2.cpp:491:17: error: cannot convert ‘void (test::*)(int) to ‘void (*)(int) in assignment
test2.cpp:496:77: error: invalid user-defined conversion from ‘test::dummy()::<lambda(int)> to ‘void (*)(int) [-fpermissive]
test2.cpp:496:28: note: candidate is: test::dummy()::<lambda(int)>::operator int (*)(int)() const <near match>
test2.cpp:496:28: note:   no known conversion for implicit ‘this parameter from ‘int (*)(int) to ‘void (*)(int)
  • 1
    Указатели на функции-члены не совпадают с указателями на функции. Вы можете увидеть в ошибке, что типы разные.
  • 0
    В дополнение к ответам ниже ... Ваша лямбда в test2.cpp не работает, потому что она возвращает int вместо void.
Теги:
class
c++11
lambda
gcc

2 ответа

1
Лучший ответ

Проблема в том, что функции-члены не являются нормальными функциями, они не могут быть назначены указателю на функцию, потому что тип, в котором они являются членами, является частью их типа. Кроме того, функция члена должна иметь объект, чтобы быть вызван, который будет this в коде функции.

У вас есть несколько решений:

  1. разрешить только функции, которые являются членами вашего класса

    void (*MyClass::func)(int); // but you can use it only with members of the class
    
  2. использовать функцию std :: function

    typedef std::function<void(int)> func;
    

Решение 2 является самым простым, поскольку функция std :: предназначена для работы со всем, что может быть вызвано с той же самой сигнатурой, что и в шаблонах parammetters. Кроме того, это единственное решение, которое позволяет хранить закрытие (объекты из лямбда). См. Обратные вызовы в стиле С++ 11? для деталей.

class test {
private:
    // variable for function pointer
    std::function< void ( int )> func;
    // default output function
    void my_default(int x) {
        cout << "x =" << "\t" << x << endl << endl;
    }

public:
    void dummy(void) {
        // 1. Test - default output function
        cout << "my_default\n";
        func = std::bind(&test::my_default, this, std::placeholders::_1);
        // or 
        func = [&]( int i ){ my_default( i ); };
        func(5);

        // 2. Test - special output function 2
        cout << "my_func2\n";
        func =  [](int x)->int{ cout << "x =" << "  " << x << endl << endl; };
        func(5);
    }
};


// entry
int main() {
    cout << "Test Programm\n\n";

    test a;
    a.dummy();

    return 0;
}
  • 0
    Спасибо за объяснение. "func = std :: bind (& my_default, this);" вернет ошибки (компилятор), но, как и Брайан Би, написал "std :: bind (& test :: my_default, this, std :: placeholder :: _ 1);" не вернет ошибок.
  • 0
    Ах да, мне всегда трудно напоминать, как использовать bind, поэтому я просто использую лямбды. Также есть mem_fun() .
Показать ещё 2 комментария
0

Функция-член не похожа на обычную функцию, поскольку должен быть экземпляр класса, доступного для его вызова (т.е. Объекта, который станет *this). Вы не можете сделать обычную переменную переменной указателя функции-члена.

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

void (test::*func)(int);

заявить об этом,

func = &test::my_default;

назначить его и

(this->*func)(5);

называть его. Конечно, теперь вы не можете указать точку указателя функции-члена на лямбду.

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

std::function<void(int)> func;

свяжите следующим образом:

func = std::bind(&test::my_default, this, std::placeholders::_1);

и затем звоните нормально. std::function работает с lambdas точно так же, как указатель функции.

  • 0
    Спасибо!! Я, наверное, забыл, в чем разница между функцией-членом и обычной функцией.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню