2015-02-19 10 views
5

Unten habe ich eine Template-Funktion namens ProxyCall, die ein Objekt akzeptiert, eine Member-Funktion und ihre Argumente. Es leitet den Aufruf einfach an die Member-Funktion weiter.Typ Abzug von const Referenzen in Vorlagenfunktionen

Ich möchte in der Lage sein, die Funktion ohne Verwendung von Vorlagequalifikationsmerkmalen aufzurufen (stellen Sie sich Tonnen solcher Aufrufe mit mehreren Argumenten vor). Die Typableitung funktioniert meistens, aber die Compiler (sowohl msvc als auch gcc 4.9) barf, wenn ich versuche, const Referenzparameter wie im Beispiel zu übergeben.

#include <string> 

struct Widget { 
    void f(const std::string& s, bool b) {} 
}; 


template<typename T, typename... Args> 
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) { 
    (obj.*method)(std::forward<Args>(args)...); 
} 


int main(int argc, char* argv[]) 
{ 
    Widget w; 
    std::string s; 

    ProxyCall<Widget, const std::string&, bool>(w, &Widget::f, s, true); // OK 
    ProxyCall(w, &Widget::f, (const std::string&)s, true); // also OK 

    ProxyCall(w, &Widget::f, s, true); // ERROR: template parameter is ambiguous 
    return 0; 
} 

Meine Frage ist: Wie kann ich den obigen Code ändern, so dass der Compiler automatisch die Typen, ohne auf explizite Template-Qualifikation oder explizite Umwandlung ableiten würde. Es scheint, dass dies möglich sein sollte, wenn man bedenkt, dass der Compiler bereits die genauen Argumenttypen aus der Signatur von Widget :: f kennt.

+1

'template void ProxyCall (T & obj, M Methode, Args && ... args) ' – zch

+1

oder alternativ' template void ProxyCall (T & obj, void (T: : * Methode) (Margs ...), Args && ... Argumente) ' – zch

Antwort

3
template<typename T, typename... Args> 
void ProxyCall(T &obj, void(T::*method)(Args...), Args&&... args) { 
    (obj.*method)(std::forward<Args>(args)...); 
} 

Args wird sowohl aus dem zweiten Argumente und die Hinter Argumenten ProxyCall abgeleitet.
In Ihrem dritten Fall, da s nicht const ist, wird Args auf [std::string&, bool] abgeleitet (rufen Sie die Regeln für Referenzzusammenbruch und Weiterleiten von Referenzen auf). Die Signatur der Mitgliedsfunktionen unterscheidet sich jedoch deutlich. Somit werden für den ersten Typ in Args zwei verschiedene Typen abgeleitet, was zu einem Deduktionsfehler führt.

Stattdessen machen sowohl die Parametertypen und die unabhängigen Argumente - und das Objekt Argument weiterleiten, im Interesse des ref-Qualifier:

template<typename T, typename F, typename... Args> 
void ProxyCall(T&& obj, F method, Args&&... args) { 
    (std::forward<T>(obj).*method)(std::forward<Args>(args)...); 
}