wskaźnik na dowolną funkcję / metodę. Jak to uzyskać?

0

Witam. Mam załóżmy sobie klasę, w której muszę użyć funkcji zdefiniowanej przez użytkownika mającą postać int(string, string)
Jak zrobić wskaźnik do funkcji, aby można było podać nazwę funkcji jak i metody ?

0

Co to znaczy podać nazwę funkcji jak i metody?
Pokaż konkretny przykład co chciałbyś uzyskać.

2

Jeżeli ktoś będzie chciał użyć metody, niech użyje std::bind lub lambd. Lub obu.

0
typedef int( * GetLengthFunc )( void );

class Klasa{
    public:
        Klasa(GetLengthFunc newFunc);
        GetLengthFunc GetLength;
};

Klasa::Klasa(GetLengthFunc newFunc){
    GetLength = newFunc;
}
/// funkcja zadziała prawidłowo jako argument kontruktora
int funkcja(){return 100;}
/// metoda nie zadziala prawidlowo
class myClass{
    public:
        int metoda(){return 100;}
}

jak zrobić, abym zarówno metody jak i funkcje mógł przekazywać do konstruktora?

3

Możesz użyć std::function + std::bind / lambda:
https://oopscenities.net/2012/02/24/c11-stdfunction-and-stdbind/

Możesz użyć zwykłego szablonu (który przyjmie wszystko jak leci - funktor, funkcję, lambdę).

std::bind możesz użyć do konwersji metody na funktor: http://en.cppreference.com/w/cpp/utility/functional/bind
(szukaj print_sum)

0

Dobra to mam lekturkę, dozobaczenia wszystkim xd już 5 raz przymierzam się do lambd i przegrywam. Ale widze nie mam wyboru.

0

Ehh, nie bardzo rozumiem chyba te lambdy. Funkcja int(void) odpowiada typowi przekazanemu do kontruktora klasy. Przekazuję adres funkcji.
Macie pomysły, co jest źle? Proszę tylko o naprostowanie mojego toku myślenia ^^

KOD na którym to sprawdzam:

#include <iostream>
using namespace std;
typedef int( * FUNCGETSIZE )( void );

class KLASA1{
    public:
        KLASA1(FUNCGETSIZE newFoo);
        FUNCGETSIZE Foo;
        void SetA();
    private:
        int a;
};
KLASA1::KLASA1(FUNCGETSIZE newFoo){
    Foo = newFoo;
}
void KLASA1::SetA(){
    a = Foo();
    cout << a << endl;
}

class KLASA2{
    public:
        KLASA2();
        int GetSize();
        void PlusA();
    private:
        int a;
};
KLASA2::KLASA2(){
    a = 0;
}
int KLASA2::GetSize(){
    return a;
}
void KLASA2::PlusA(){
    ++a;
}

int main()
{///
    class KLASA2 *k2 = new KLASA2();
    class KLASA1 *k1 = new KLASA1(
                [](void)->int{ return k2.GetSize(); }
             );

    k1->SetA();
    k2->PlusA();
    k1->SetA();
    k2->PlusA();
    k1->SetA();
    k2->PlusA();
    k1->SetA();
    k2->PlusA();

    delete k1;
    delete k2;
    return 0;
}

 

ERROR:

C:\Users\Świdwa\Desktop\Untitled1.cpp|45|error: 'k2' is not captured|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

4

Lambda ma pusty capture-list, a próbujesz użyć k2, które ani nie jest parametrem, ani elementem capture-list.

0

Czyli według http://www.umich.edu/~eecs381/handouts/Lambda.pdf
mogę zrobić tak?

class KLASA2 *k2 = new KLASA2();
    auto it = [k2](void)->int{ return k2->GetSize();};
    class KLASA1 *k1 = new KLASA1(
                 it
             );

    k1->SetA();
    k2->PlusA();
 

teraz nie pasuje mi typ przekazywany do konstruktora :(

C:\Users\Świdwa\Desktop\Untitled1.cpp||In function 'int main()':|
C:\Users\Świdwa\Desktop\Untitled1.cpp|45|error: no matching function for call to 'KLASA1::KLASA1(main()::__lambda0&)'|
C:\Users\Świdwa\Desktop\Untitled1.cpp|45|note: candidates are:|
C:\Users\Świdwa\Desktop\Untitled1.cpp|13|note: KLASA1::KLASA1(FUNCGETSIZE)|
C:\Users\Świdwa\Desktop\Untitled1.cpp|13|note: no known conversion for argument 1 from 'main()::__lambda0' to 'FUNCGETSIZE {aka int (*)()}'|
C:\Users\Świdwa\Desktop\Untitled1.cpp|5|note: constexpr KLASA1::KLASA1(const KLASA1&)|
C:\Users\Świdwa\Desktop\Untitled1.cpp|5|note: no known conversion for argument 1 from 'main()::__lambda0' to 'const KLASA1&'|
C:\Users\Świdwa\Desktop\Untitled1.cpp|5|note: constexpr KLASA1::KLASA1(KLASA1&&)|
C:\Users\Świdwa\Desktop\Untitled1.cpp|5|note: no known conversion for argument 1 from 'main()::__lambda0' to 'KLASA1&&'|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Z pewnością

typedef int( * FUNCGETSIZE )( void ); 

nie pasuje do:auto it = k2->int{ return k2->GetSize();};

Ale jak temu zaradzić?
4

Tylko lambdy z pustymi capture-list można rzutować na wskaźnik na funkcję. Jak chcesz catch-all to musisz użyć std::function. Przy okazji, używaj czytelniejszego syntaxu C++11:

using FUNCGETSIZE  = int(*)(void);
1

Zamień:

typedef int(*FUNCGETSIZE)(void);

na:

typedef std::function<int(void)> FUNCGETSIZE;
0

To w takim razie powinno to wyglądać chyba tak:

using FUNCGETSIZE  = std::function<int(void)>; 
function<int(void)> FOO = k2->GetSize;
    class KLASA1 *k1 = new KLASA1(
                 FOO
             );
 

BŁEDY:

C:\Users\Świdwa\Desktop\Untitled1.cpp||In function 'int main()':|
C:\Users\Świdwa\Desktop\Untitled1.cpp|46|error: conversion from '<unresolved overloaded="overloaded" function="function" type="type">' to non-scalar type 'std::function<int()>' requested|
||=== Build failed: 1 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

Niestety. Kompletnie tego nie czaję. Postaram sie jutro poczytać jeszcze jakieś artykuły może coś mi wpadnie do głowy i się odezwę jak nie dam rady.

0

AAAAAAAA MAM !
Połączyłem function z lambdą i działa !!!!!!!!!

 
function<int(void)> FOO = [k2](void)->int{ return k2->GetSize();};
class KLASA1 *k1 = new KLASA1( FOO );
0

Bardzo Wam dziekuję chłopaki za pomoc. Mogę iść w spokoju spać :)

Ostatnie pytanie: Skad lambda wie, jaka wartość zwrócić?

function<int(void)> FOO = [k2] { return k2->GetSize(); };
0

Panowie mam kolejną zagwostkę:
mam procedurę zadeklarowana w klasie:

LRESULT CALLBACK SEARCHEDIT::SubEditProc( HWND hwnd, UINT mesg, WPARAM wParam, LPARAM lParam ) 

i muszę dokonać subclassingu Edita.

Zrobiłem coś takiego:

auto it = [this](HWND hwnd, UINT mesg, WPARAM wParam, LPARAM lParam)->LRESULT CALLBACK{ return 0;};
function<LRESULT CALLBACK(HWND, UINT, WPARAM, LPARAM)> SubFunc = it;

DefaultProc = ( WNDPROC ) SetWindowLongPtr( hEdit, GWLP_WNDPROC,( LONG ) it );
 

||=== Build: Release in WH_GDI (compiler: GNU GCC Compiler) ===|
C:\Users\Świdwa\Desktop\Programy\WH_GDI\wh_SearchEdit.cpp||In member function 'bool SEARCHEDIT::Create(int, int, int, int, HWND, int)':|
C:\Users\Świdwa\Desktop\Programy\WH_GDI\wh_SearchEdit.cpp|75|error: variable 'std::function<long int(HWND__*, unsigned int, unsigned int, long int)> SubFunc' has initializer but incomplete type|
C:\Users\Świdwa\Desktop\Programy\WH_GDI\wh_SearchEdit.cpp|77|error: invalid cast from type 'SEARCHEDIT::Create(int, int, int, int, HWND, int)::__lambda0' to type 'LONG {aka long int}'|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|

Ogólnie

auto it = [this](HWND hwnd, UINT mesg, WPARAM wParam, LPARAM lParam)->LRESULT CALLBACK{ return 0;}; 

jest dobrze zrobione, ale dalej nie potrafię wsadzić tego do funkcji SetWindowPtr(). Ponad to, zależy mi na wsadzeniu tam nie lambdy, tylko metody: LRESULT CALLBACK SEARCHEDIT::SubEditProc( HWND hwnd, UINT mesg, WPARAM wParam, LPARAM lParam )

Mogę prosić o drobną wskazówkę?
0

CALLBACK to calling convention, nie wiem jak to w lambdzie zadeklarować, standard tego nie przewiduje. Rozwiązanie dla msvc: http://stackoverflow.com/questions/18367641/use-createthread-with-a-lambda

0

A znasz inne rozwiązanie jak sprawić, aby metoda była widziana jako zwykła funkcja?

1

Metoda to nie jest zwykła funkcja, nie może być tak widziana (musi dostać niejawne this)

1

Wygląda na to że próbujesz skonwertować std::function (a raczej lambdę) na LONG, mam wątpliwości czy to jest takie proste.

Zajrzyj tutaj:
http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html

1 użytkowników online, w tym zalogowanych: 0, gości: 1