2016-02-10 19 views
6

Quando si compila il seguente codice:non può chiamare generico membro std :: funzione dalla classe modello

#include <functional> 

template <typename functionSignature> 
class Class 
{   
    std::function<functionSignature> func; 
public: 
    Class(const std::function<functionSignature>& arg) : func(arg) {} 
    void callFunc() { func(); } 
}; 

void f(const int i) {} 

int main() 
{ 
    Class<void(const int)> a(std::bind(f, 10)); 
    a.callFunc(); 
    return 0; 
} 

Il compilatore VS 2015 genera il seguente messaggio di errore alla sesta riga:

error C2064: term does not evaluate to a function taking 0 arguments. 

Ora, Credo che questo sia dovuto al fatto che il compilatore pensa che lo functionSignature non sia, beh, una firma di funzione; lo stesso errore si verifica quando istanziato e provo a chiamare operator() su un std::function<int> invece di std::function<int()>, per esempio.

Come posso garantire che l'argomento del modello sarà sempre una firma di funzione, in modo che io possa chiamare operator() su std::function?

+0

Per favore, puoi aggiornare il codice esattamente come si sta chiamando la classe e come si inizializza la classe? – Jts

+0

Sì, un MCVE effettivo sarebbe d'aiuto. Basta aggiungere un 'main' giocattolo che crea un'istanza del tuo' Class 'quindi esegue' .callFunc() 'e conferma che compila e genera l'errore in MSVC. – Yakk

risposta

2

Il tuo errore è qui:

Class<void(const int)> a(std::bind(f, 10)); 

La funzione Class::callFunc() invoca func() - cioè, senza argomenti. Il risultato di std::bind(f, 10) è anche una funzione che non accetta argomenti, che è coerente con l'argomento del modello per il modello di classe. L'utilizzo di Class<void(const int)> non è coerente con l'utilizzo nel modello di classe e l'inizializzazione.

La soluzione è semplice: modificare la linea errante per

Class<void()> a(std::bind(f, 10)); 
+0

Bene, dato che l'OP ha cambiato la domanda originale, la mia prima risposta ha ancora senso, ma questa è davvero più focalizzata. – skypjack

+1

@skypjack - Non c'era molto da dire nel momento in cui hai scritto la tua risposta. Leggi la mente dell'OP, e poi alcuni. +1, sulla tua risposta, cioè. –

6

ho il sospetto che si desidera qualcosa di simile:

template <typename F> 
class Class; 

template<typename R, typename... P> 
class Class<R(P...)> { 
public: 
    std::function<R(P...)> func; 
    void callFunc(P... p) { func(p...); } 
}; 

Utilizzando specializzazione parziale in questo modo si può facilmente definire il tipo che si desidera.
A titolo di esempio, è possibile utilizzarlo come:

Class<int(double)> c; 

Naturalmente, ho notato che non avete costruttori per la classe, in modo da invocare func non è una buona idea, ma è abbastanza facile da definire e passare una funzione adeguata come argomento.

Ne consegue un esempio completo e funzionante in cui ho usato il operator() per richiamare la funzione:

#include <functional> 

template <typename F> 
class Class; 

template<typename R, typename... P> 
class Class<R(P...)> { 
public: 
    Class(std::function<R(P...)> f): func{f} { } 
    void operator()(P... p) { func(p...); } 
private: 
    std::function<R(P...)> func; 
}; 

void fn() { } 

int main() { 
    std::function<void()> f = fn; 
    Class<void()> c{f}; 
    c(); 
} 
+0

+1, questo ha risposto alla domanda su cui ho cercato su google e quella su cui ho pensato si basava sul titolo della domanda. – AnorZaken

1

E 'questo ciò che si sta cercando di fare?

http://ideone.com/fork/IZ0Z1A

Se functionSignature non è una funzione, la funzione std :: si generano errori quando si crea classe, ma si potrebbe aggiungere un costruttore e buttare là un static_assert(std::is_function<functionSignature>::value == true," "); se vuoi immagino.

#include <functional> 
#include <iostream> 

template <typename functionSignature> 
class Class 
{ 
public: 
    std::function<functionSignature> func; 
    void callFunc() { func(); } 
}; 

void f() 
{ 
    std::cout << "hello" << std::endl; 
} 

int main() 
{ 
    Class<decltype(f)> t {f}; 
    t.callFunc(); 

    return 0; 
}