2015-04-28 19 views
10

Chciałbym zaimplementować wywołanie funkcji, które działa tak jak konstruktor thread. Na przykładWywołanie funkcji uniwersalnej C++

std::thread second (bar,0); 

rozpocznie wątku, który wywołuje bar z jednym argumentem 0. Chciałbym zrobić to samo, ale nie wiem jak.

Na przykład, biorąc pod uwagę:

void myFunc(int a){ 
    cout << a << endl; 
} 

Chciałbym:

int main() { 
    caller(myFunc,12); 
} 

zadzwonić myFunc z parametrem 12.

+6

'std :: function' i' std :: bind'? –

+0

rozważyć sygnał/gniazdo? – user3528438

+1

Dla C++ 17, będzie ['std :: invoke()'] (http://en.cppreference.com/w/cpp/utility/functional/invoke), który robi dokładnie to. – DanielKO

Odpowiedz

21

wykona obiekt wywoływalny z dowolnego obiektu wywoływalnego z dowolnym zbiorem parametrów, tak jak robi to konstruktor thread. Więc po prostu owinąć że w funkcji, która nazywa go:

template <typename... Args> 
auto caller(Args &&... args) { 
    return std::bind(std::forward<Args>(args)...)(); 
} 

Należy pamiętać, że auto typ zwracany wymaga C++ 14 lub później. W przypadku C++ 11 musisz albo zwrócić void, albo określić typ:

auto caller(Args &&... args) 
    -> decltype(std::bind(std::forward<Args>(args)...)()) 
+0

Czy mogę wywołać metodę z obiektu za pomocą tego? –

+2

@MaxianNicu: Tak. Dla funkcji składowej 'Class :: method()' i obiektu 'object' wywołaj to za pomocą' caller (& Class :: method, & object) '. –

+0

Świetnie. Zadziałało. Dzięki. –

7

Jeśli wszystko, co chcesz zrobić, to zadzwonić do dowolnej funkcji z dowolnego argumentu, że to tylko szablon na obu typach:

template <typename Function, typename Arg> 
void call_with_one(Function&& f, Arg&& arg) { 
    f(std::forward<Arg>(arg)); 
} 

który można rozszerzyć, aby zadzwonić z dowolną liczbą args przez co o zmiennej liczbie argumentów :

template <typename Function, typename... Arg> 
void call_with_any(Function f, Arg&&... args) { 
    f(std::forward<Arg>(args)...); 
} 

Albo naprawdę f powinno być odniesienie spedycja także:

template <typename Function, typename... Arg> 
void call_with_any(Function&& f, Arg&&... args) { 
    std::forward<Function>(f)(std::forward<Arg>(args)...); 
} 

Należy zauważyć, że działa to tylko z funkcjami i obiektami implementującymi operator(). Jeśli f jest wskaźnikiem do elementu, to się nie powiedzie - będziesz musiał zamiast tego użyć std::bind jako sugestii Mike Seymour.

+0

Proponuję również zajęcie 'f' przez odniesienie do przekazywania. – Quentin

+2

Aby działał "tak jak konstruktor" wątku ", musi również działać, jeśli' f' jest wskaźnikiem funkcji elementu. –

+0

@MikeSeymour Linkowałby raczej do twojej odpowiedzi niż kopiowania :) – Barry