2012-04-20 12 views
15

reducido código de ejemplo:plantillas variadic con el parámetro 'const' sobrecarga

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

Resultados previstos:

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

salida real:

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

Así que de alguna manera el const calificador de la función parámetro se pierde cuando se pasa a través de la plantilla variadic. ¿Por qué? ¿Cómo puedo prevenir esto?

PD: probado con GCC 4.5.1 y SUSE 11,4

+0

No tiene nada que ver con las plantillas variadic. Los parámetros del proxy de su plantilla de función no son referencias, por lo que la const de los argumentos de la función se ignora al deducir los argumentos de la plantilla. – Cosyn

Respuesta

18

Sólo se tropiezan con la forwarding problem. Este problema se resuelve usando perfect forwarding.

Básicamente, usted necesita tomar sus parámetros por valor p-referencia, y se basan en std::forward que transmita correctamente ellos, manteniendo su naturaleza:

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

¿No necesita 'std :: forward '? – juanchopanza

+0

@juanchopanza No. Eso pasaría todos los argumentos de tipo a 'std :: forward', pero' std :: forward' tiene solo un argumento de tipo. –

+0

@ R.MartinhoFernandes Derecha, forward también toma solo un parámetro, así que supongo que necesitamos 'func (std :: forward (args) ...); 'o algo así? la muestra en la respuesta no se compila en mi instantánea gcc4.7. – juanchopanza

6

Como Luc ya se ha mencionado este es un problema de reenvío y la respuesta a cómo prevenirlo es usar reenvío perfecto. Pero trataré de abordar las otras preguntas al final:

De alguna manera, el calificador const del parámetro de función se pierde cuando se pasa a través de la plantilla variadic. ¿Por qué?

Esto tiene todo que ver con la inferencia de tipo. No haga caso de que esté utilizando plantillas variadic y considerar la plantilla más simple argumento:

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

En el lugar de llamada que tiene one_arg_proxy(5), es decir, el argumento es un intrvalue. La inferencia de tipos se activa para averiguar cuál es el tipo T debe ser, y las reglas dictan que T es int, por lo que la llamada se traduce a one_arg_proxy<int>(5) y la creación de instancias de la plantilla que se compila es:

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

Ahora el llamar a func toma un argumento lvalue, y por lo tanto la versión de func teniendo una referencia no const es una mejor correspondencia (no hay conversiones necesarias) que el que toma una const&, que arroje el resultado de que está recibiendo. El problema aquí es que func no se llama con el argumento proxy, sino con la copia interna que proxy hizo de él.

Cuestiones relacionadas