2015-10-03 15 views
6

Il concetto di callable è definito in http://en.cppreference.com/w/cpp/concept/Callable.In C++ 11, come richiamare un oggetto callable arbitrario?

Supponiamo Ho una richiamabile oggetto f che ha un argomento di tipo T * e tipo vuoto ritorno. f può essere qualsiasi tipo richiamabile (un oggetto funzione, un puntatore alla funzione membro, un puntatore al membro dati, ecc.). Come posso invocare f?

La semplice chiamata f (x) non riesce poiché f può essere un puntatore alla funzione membro o membro dati. C'è un modo semplice per chiamare f? Una possibile soluzione è std :: bind (f, x)(), ma questa soluzione diventa più complessa quando f ha più argomenti.

+0

Hai un caso d'uso? –

risposta

6

Questo è esattamente ciò che fa std::invoke, ma non sarà standard fino a C++ 17. Puoi creare la tua versione, ma può essere piuttosto complicata se è completamente generale.

Ecco l'idea di base per due casi (codice preso dal cppreference.com):

template <class F, class... Args> 
inline auto INVOKE(F&& f, Args&&... args) -> 
    decltype(std::forward<F>(f)(std::forward<Args>(args)...)) { 
     return std::forward<F>(f)(std::forward<Args>(args)...); 
} 

template <class Base, class T, class Derived> 
inline auto INVOKE(T Base::*pmd, Derived&& ref) -> 
    decltype(std::forward<Derived>(ref).*pmd) { 
     return std::forward<Derived>(ref).*pmd; 
} 
+0

È implementato in gcc 5.2? – user3547691

+0

Penso di poter semplicemente copiare la possibile implementazione fornita in http://en.cppreference.com/w/cpp/utility/functional/invoke. Grazie. – user3547691

+0

Per la cronaca, apparentemente MSVC2015 ha la sua piena implementazione. – Adrian17

3

Invece di attuazione INVOKE te, utilizzare uno dei library features that uses it. In particolare, funziona std::reference_wrapper. Così si può avere l'effetto di std::invoke(f, args...) con std::ref(f)(args...):

template<typename F, typename... Args> 
auto invoke(F f, Args&&... args) 
    -> decltype(std::ref(f)(std::forward<Args>(args)...)) 
{ 
    return std::ref(f)(std::forward<Args>(args)...); 
} 

non l'ho fatto avanti f perché std::reference_wrapper richiede che l'oggetto passato in non è un rvalue. L'utilizzo di std::bind anziché std::ref non risolve il problema. Ciò significa che per un oggetto funzione come questa:

struct F 
{ 
    void operator()() && { 
     std::cout << "Rvalue\n"; 
    } 
    void operator()() const& { 
     std::cout << "Lvalue\n"; 
    } 
}; 

invoke(F{}) stamperà Lvalue, mentre std::invoke(F{}) in C++ 17 sarebbe stampare Rvalue.

ho trovato la tecnica da this paper