2011-11-25 16 views
10

He estado usando una plantilla variadic que actúa como un firewall de excepción en una interfaz entre C y C++. La plantilla simplemente toma una función, seguida de N argumentos y llama a la función dentro de un bloque try catch. Esto ha funcionado bien, lamentablemente una de las funciones a las que deseo llamar ahora toma un argumento predeterminado adicional. Como resultado, el nombre de la función no se resuelve y la plantilla no se puede compilar.Plantillas variables, reenvío perfecto a funciones con argumentos predeterminados

El error es:

perfect-forward.cpp: In function ‘void FuncCaller(Func, Args&& ...) [with Func = void (*)(const std::basic_string<char>&, double, const std::vector<int>&), Args = {const char (&)[7], double}]’ :
perfect-forward.cpp:69:41: instantiated from here
perfect-forward.cpp:46:4: error: too few arguments to function

Una versión simplificada del código es el siguiente:

template< class Func, typename ...Args > 
void FuncCaller(Func f, Args&&... params) 
{ 
    try 
    { 
     cout << __func__ << " called\n"; 
     f(params...); 
    } 
    catch(std::exception& ex) 
    { 
     cout << "Caught exception: " << ex.what() << "\n"; 
    } 
} 

void Callee(const string& arg1, double d, const vector<int>&v = vector<int>{}) 
{ 
    cout << __func__ << " called\n"; 
    cout << "\targ1: " << arg1 << "\n"; 
    cout << "\td: " << d << "\n"; 
    cout << "\tv: "; 
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " " )); 
    cout << "\n"; 
} 

int main() 
{ 
    vector<int> v { 1, 2, 3, 4, 5 }; 

    FuncCaller(Callee, "string", 3.1415, v); 
    FuncCaller(Callee, "string", 3.1415); **// Fails to compile** 

    return 0; 
} 

En caso de que este código funcione o estoy esperando demasiado de que el compilador?

Nota: He probado la utilización de perfecta reenvío con los constructores que tienen los argumentos por defecto y el código se compila y funciona como se espera,

es decir:

template<typename TypeToConstruct> struct SharedPtrAllocator 
{ 
    template<typename ...Args> shared_ptr<TypeToConstruct> 
     construct_with_shared_ptr(Args&&... params) { 
     return std::shared_ptr<TypeToConstruct>(new TypeToConstruct(std::forward<Args>(params)...)); 
    }; 
}; 

obras cuando se llama al constructor cfollowing con 2 o 3 argumentos ...

MyClass1(const string& arg1, double d, const vector<int>&v = vector<int>{}) 
+2

(Debería ser 'f (std :: forward (params) ...);', por cierto.) –

Respuesta

8

No creo que haya ninguna manera de lograr esto. Los valores de argumento predeterminados no son parte de la firma de la función. Son solo abreviaturas de generación de código que el compilador amplía cuando llama a la función literalmente. Del mismo modo, std::bind no recogerá argumentos predeterminados, tampoco.

+1

Pensé que era algo largo esas líneas ... Fuera de interés ¿por qué el reenvío a un constructor con argumentos predeterminados? – mark

+1

Bueno, puede llamar a la función directamente, que es lo que hace su código (si descifra todas las sustituciones de parámetros de la plantilla). Pero en la pregunta original, el tipo de función en sí se deduce, y ahí es donde se pierde el argumento predeterminado. –

Cuestiones relacionadas