2012-04-20 4 views
15

Reduzierte Beispielcode Überlastung:Variadische Vorlagen mit 'const' Parameter

#include <iostream> 

template<typename T> 
void func(T &x) 
{ 
    std::cout << "non-const " << x << std::endl; 
} 

template<typename T> 
void func(const T &x) 
{ 
    std::cout << "const " << x << std::endl; 
} 

template<typename ...ARGS> 
void proxy(ARGS ...args) 
{ 
    func(args...); 
} 

int main() 
{ 
    int i = 3; 

    func(i); 
    func(5); 
    func("blah"); 

    proxy(i); 
    proxy(5); 
    proxy("blah"); 
} 

Erwartete Ausgabe:

non-const 3 
const 5 
const blah 
non-const 3 
const 5 
const blah 

tatsächliche Ausgang:

non-const 3 
const 5 
const blah 
non-const 3 
non-const 5 
non-const blah 

also irgendwie die const Qualifier der Funktion Der Parameter geht verloren, wenn er durch die Variadic-Vorlage gesetzt wird. Warum? Wie kann ich das verhindern?

PS: getestet mit GCC 4.5.1 und SUSE 11,4

+0

Es hat nichts mit variadischen Vorlagen zu tun. Die Parameter Ihres Funktionsschablonen-Proxys sind keine Referenzen, daher wird das const der Funktionsargumente beim Ableiten der Vorlagenargumente ignoriert. – Cosyn

Antwort

18

Sie stolpern gerade auf dem forwarding problem. Dieses Problem wird mit perfect forwarding gelöst.

Grundsätzlich müssen Sie Ihre Parameter von R-Wert-Referenz nehmen, und verlassen sich auf std::forward richtig, sie zu übermitteln, während ihre Natur zu halten:

template<typename ...Args> 
void proxy(Args&& ...args) 
{ 
    func(std::forward<Args>(args)...); 
} 
+0

Brauchen Sie nicht 'std :: forward '? – juanchopanza

+0

@juanchopanza Nein. Das würde alle Typargumente an "std :: forward" übergeben, aber "std :: forward" hat nur ein Typargument. –

+0

@ R.MartinhoFernandes Richtig, vorwärts braucht auch nur einen Parameter, also brauchen wir 'func (std :: forward (args) ...) oder so etwas? Das Beispiel in der Antwort kompiliert nicht auf meinem gcc4.7-Snapshot. – juanchopanza

6

Wie Luc bereits erwähnt, ist dies ein Problem der Weiterleitung und die Antwort zu wie man es verhindert ist zu verwenden perfekte Weiterleitung. Aber ich werde versuchen, die anderen Fragen am Ende zu adressieren:

So irgendwie geht das Const-Qualifikationsmerkmal des Funktionsparameters verloren, wenn es durch die Variadic-Vorlage gestellt wird. Warum?

Dies hat alles mit Typschluss zu tun. Ignorieren, dass Sie variadische Vorlagen und betrachten die einfachste Argument Vorlage:

template <typename T> 
void one_arg_proxy(T arg) { 
    func(arg); 
} 

An der Stelle des Anrufs Sie one_arg_proxy(5) haben, das heißt, das Argument ein intrvalue. Typinferenz tritt, um herauszufinden, was der Typ T sein sollte, und die Regeln diktieren, dass T ist int, so der Aufruf von one_arg_proxy<int>(5) übersetzt wird und die Instanziierung der Vorlage, die erstellt wird ist:

template <> 
void one_arg_proxy<int>(int arg) { 
    func(arg); 
} 

Nun ist die Aufruf an func dauert ein lvalue Argument, und damit die Version func eine nicht-const Referenz ist eine bessere Übereinstimmung (keine Konvertierungen erforderlich) als die, die eine const&, das Ergebnis, das Sie erhalten. Das Problem hierbei ist, dass func nicht mit dem Argument proxy aufgerufen wird, sondern mit der internen Kopie, die proxy daraus gemacht wird.