2016-02-10 13 views
6

Kompilując następujący kod:Nie można wywołać ogólny element std :: function z klasy szablonu

#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; 
} 

VS 2015 kompilator generuje następujący komunikat o błędzie w wierszu szóstym:

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

Teraz Wierzę, że dzieje się tak, ponieważ kompilator uważa, że ​​functionSignature nie jest, no cóż, podpisem funkcji; ten sam błąd występuje, gdy tworzę instancję i próbuję wywołać na przykład operator() na std::function<int> zamiast na std::function<int()>.

Jak mogę zagwarantować, że argument szablonu zawsze będzie sygnaturą funkcji, abym mógł zadzwonić pod numer operator() na std::function?

+0

Czy możesz zaktualizować swój kod dokładnie tak jak ty dzwonisz swoją klasę i jak zainicjować swoją klasę? – Jts

+0

Tak, rzeczywiste MCVE mogłoby pomóc. Po prostu dodaj zabawkę 'main', która tworzy instancję' Class ', następnie wykonaj' .callFunc() 'i potwierdź, że kompiluje i generuje błąd w MSVC. – Yakk

Odpowiedz

2

Twój błąd jest tutaj:

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

Funkcja Class::callFunc() wywołuje func() - czyli żadnych argumentów. Wynik std::bind(f, 10) jest także funkcją, która nie przyjmuje żadnych argumentów, co jest zgodne z argumentem szablonu szablonu klasy. Używanie Class<void(const int)> jest niezgodne zarówno z użyciem w szablonie klasy, jak i podczas inicjowania.

Rozwiązanie jest proste: Zmiana błędny linię do

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

Cóż, skoro OP zmienił pierwotne pytanie, moja pierwsza odpowiedź nadal ma sens, ale ta jest bardziej skupiona. – skypjack

+1

@skypjack - W chwili pisania odpowiedzi nie było wiele do zrobienia. Czytasz umysł OP, a potem trochę. +1, na twoją odpowiedź, to znaczy. –

6

Podejrzewam chcesz coś takiego:

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...); } 
}; 

za pomocą częściowej specjalizacji w ten sposób można łatwo określić rodzaj chcesz.
Jako przykład, można go używać jako:

Class<int(double)> c; 

Oczywiście, zauważyłem, że nie masz konstruktorów dla swojej klasy, tak aby wywołać func nie jest dobrym pomysłem, ale jest to dość łatwe do zdefiniowania i przekazują właściwą funkcję jako argument.

Wynika kompletny i pracy przykład gdzie Użyłem operator() aby wywołać funkcję:

#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, To odpowiadało na pytanie, na które się wyszukałem, i ten, o którym myślałem, że jest oparty na tytule pytania. – AnorZaken

1

Czy to, co staramy się robić?

http://ideone.com/fork/IZ0Z1A

Jeśli functionSignature nie jest funkcją, std :: funkcja rzuci błędów podczas tworzenia klasy, ale można dodać konstruktora i wrzucić tam static_assert(std::is_function<functionSignature>::value == true," "); jeśli chcesz chyba.

#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; 
}