2017-07-27 6 views
0

Aufgrund meiner vorherigen Frage hier Variadic template, function as argumenteine variadische Template-Funktion mit einer Elementfunktion

Aufruf habe ich unten mit einer einfachen Klasse endete, aber wie verwende ich std :: aufrufen oder eine andere Methode Tester zu nennen: : Test mit Tester :: einfach als Argument? Die Beispiele, die unter http://en.cppreference.com/w/cpp/utility/functional/invoke#Example zur Verfügung gestellt wurden, waren nicht sehr hilfreich für mich und ich versuchte viele verschiedene Arten, std :: invoke zu verwenden.

class Tester { 
public: 
    template<typename F, typename... Args> 
    decltype(auto) test(F&& f, Args&&... args) { 
     return std::forward<F>(f)(std::forward<Args>(args)...); 
    } 
    int simple(int i) { return i; } 
}; 

int main() 
{ 
    Tester t; 
    std::cout << t.test(t.simple, 3); // how do you modify this line such that the code compiles? 
} 

Vielen Dank!

Antwort

2

Eine Möglichkeit ist die Definition Ihrer test() Elementfunktion zu modifizieren, wie so:

class Tester { 
public: 
    template<typename F, typename... Args> 
    decltype(auto) test(F&& f, Args&&... args) { 
     return std::invoke(std::forward<F>(f), std::forward<Args>(args)...); 
    } 
    int simple(int i) { return i; } 
}; 

Wir können dann als zweites Mitglied Funktionszeiger auf test(), mit der Instanz, auf das die Methode aufgerufen werden passieren soll Argument, und dann werden die Funktionsargumente selbst:

int main() 
{ 
    Tester t; 
    std::cout << t.test(&Tester::simple, t, 3); 
} 

Der Grund dieser Arbeiten ist, weil std::invoke eine special overload for pointers-to-members hat, so dass

std::invoke(ptr-to-member, instance, args...); 

als

(instance.*ptr-to-member)(args...); 

genannt das ist genau das, was wir in diesem Fall wollen.

1

Hinweis, dass std::invoke ein Teil von C++ 17 ist. Im Fall, wenn es nicht verfügbar ist, könnte man test Funktion implementieren, so dass es eine Zeiger-to-Mitglied-Funktion und eine Instanz einer Klasse akzeptiert:

template<typename F, typename T, typename... Args> 
decltype(auto) test(F f, T&& t, Args&&... args) { 
    return (std::forward<T>(t).*f)(std::forward<Args>(args)...); 
} 

Jetzt test akzeptiert eine Zeiger-to- member-function als erstes Argument, eine Instanz einer Klasse als zweites Argument und eine beliebige Anzahl zusätzlicher Argumente.

Dann test könnte wie genannt werden:

Tester t; 
std::cout << t.test(&Tester::simple, t, 42); 

WANDBOX EXAMPLE

+0

Es ist jetzt nicht kompatibel mit Nichtmitgliedsfunktionen. Versuchen Sie 't.test (puts," Hallo! ")'. –

+0

@HenriMenke ja, genau. Soweit ich das verstehe, interessiert sich OP in dieser Frage für den Umgang mit Mitgliedsfunktionen. Also habe ich eine einfache Lösung für die Member-Funktion hinzugefügt. Nun kann OP Lösungen aus beiden Fragen kombinieren, um die gewünschte Funktionalität zu erreichen. Oder benutzen Sie einfach 'std :: invoke', wenn sein Compiler es ihm erlaubt :) –

1

Nur noch eine weitere Möglichkeit zu erwähnen, könnten Sie die Mitgliedsfunktionsaufruf in einem Lambda-wickeln und die Instanz t erfassen. In C++ 14 können wir das generische Lambda dafür verwenden, so dass wir die Parameter nicht explizit spezifizieren müssen.

#include <iostream> 
#include <utility> 

class Tester { 
public: 
    template<typename F, typename... Args> 
    decltype(auto) test(F&& f, Args&&... args) { 
     return std::forward<F>(f)(std::forward<Args>(args)...); 
    } 
    int simple(int i) { return i; } 
}; 

int main() 
{ 
    Tester t; 
    std::cout << t.test([&t] (auto&&... args) { return t.simple(std::forward<decltype(args)>(args)...); }, 3); 
} 
Verwandte Themen