Argumentos de plantilla predeterminados para plantillas de funciones

¿Por qué los argumentos de plantilla predeterminados solo se permiten en plantillas de clase? ¿Por qué no podemos definir un tipo predeterminado en una plantilla de función miembro? Por ejemplo:

struct mycclass { template void mymember(T* vec) { // ... } }; 

En cambio, C ++ obliga a que los argumentos de plantilla predeterminados solo se permitan en una plantilla de clase.

Tiene sentido dar argumentos de plantilla por defecto. Por ejemplo, podría crear una función de clasificación:

 template::value_type> > void sort(Iterator beg, Iterator end, Comp c = Comp()) { ... } 

C ++ 0x los presenta a C ++. Vea este informe de defectos de Bjarne Stroustrup: Argumentos de plantilla predeterminados para plantillas de funciones y lo que dice

La prohibición de los argumentos de plantilla predeterminados para las plantillas de funciones es un remanente mal concebido del tiempo en que las funciones independientes se trataron como ciudadanos de segunda clase y requirió que todos los argumentos de la plantilla se deduzcan de los argumentos de la función en lugar de especificados.

La restricción obstaculiza seriamente el estilo de progtwigción al hacer innecesariamente funciones independientes diferentes de las funciones de miembros, lo que hace más difícil escribir código de estilo STL.

Para citar plantillas de C ++: la guía completa (página 207):

Cuando las plantillas se agregaron originalmente al lenguaje C ++, los argumentos explícitos de la plantilla de función no fueron una construcción válida. Los argumentos de la plantilla de función siempre deben ser deducibles de la expresión de llamada. Como resultado, no parecía existir una razón convincente para permitir los argumentos de la plantilla de función predeterminada porque el valor deducido siempre anularía el valor predeterminado.

Hasta ahora, todos los ejemplos ofrecidos de parámetros de plantilla predeterminados para plantillas de funciones se pueden hacer con sobrecargas.

AraK:

 struct S { template  R get_me_R() { return R(); } }; 

podría ser:

 struct S { template  R get_me_R() { return R(); } int get_me_R() { return int(); } }; 

Mío:

 template  int &increment(int &i) { i += N; return i; } 

podría ser:

 template  int &increment(int &i) { i += N; return i; } int &increment(int &i) { return increment<1>(i); } 

litb:

 template > void sort(Iterator beg, Iterator end, Comp c = Comp()) 

podría ser:

 template void sort(Iterator beg, Iterator end, std::less c = std::less()) template void sort(Iterator beg, Iterator end, Comp c = Comp()) 

Stroustrup:

 template  void f(T t = 0, U u = 0); 

Podría ser:

 template  void f(S s = 0, T t = 0); template  void f(S s = 0, double t = 0); 

Lo cual probé con el siguiente código:

 #include  #include  #include  #include  template  T prettify(T t) { return t; } std::string prettify(char c) { std::stringstream ss; if (isprint((unsigned char)c)) { ss < < "'" << c << "'"; } else { ss << (int)c; } return ss.str(); } template  void g(S s, T t){ std::cout < < "f<" << typeid(S).name() << "," << typeid(T).name() << ">(" < < s << "," << prettify(t) << ")\n"; } template  void f(S s = 0, T t = 0){ g(s,t); } template  void f(S s = 0, double t = 0) { g(s, t); } int main() { f(1, 'c'); // f(1,'c') f(1); // f(1,0) // f(); // error: T cannot be deduced f(); // f(0,0) f(); // f(0,0) } 

El resultado impreso coincide con los comentarios de cada llamada a f, y la llamada comentada no se puede comstackr como se esperaba.

Por lo tanto, sospecho que los parámetros de la plantilla por defecto “no son necesarios”, pero probablemente solo en el mismo sentido en que los argumentos de la función por defecto “no son necesarios”. Como indica el informe de defectos de Stroustrup, la adición de parámetros no deducidos fue demasiado tarde para que alguien se dé cuenta y / o realmente aprecie que hizo que los valores predeterminados sean útiles. Entonces, la situación actual está en efecto basada en una versión de plantillas de funciones que nunca fue estándar.

En Windows, con todas las versiones de Visual Studio, puede convertir este error ( C4519 ) en una advertencia o deshabilitarlo de esta manera:

 #ifdef _MSC_VER #pragma warning(1 : 4519) // convert error C4519 to warning // #pragma warning(disable : 4519) // disable error C4519 #endif 

Ver más detalles aquí .

Lo que uso es el siguiente truco:

Digamos que quieres tener una función como esta:

 template  > void doStuff(ARR_E array) { E one(1); array.add( one ); } 

No se te permitirá, pero lo hago de la siguiente manera:

 template  struct MyArray_t { void add(T i) { // ... } }; template  > class worker { public: /*static - as you wish */ ARR_E* parr_; void doStuff(); /* do not make this one static also, MSVC complains */ }; template  void worker::doStuff() { E one(1); parr_->add( one ); } 

Así que de esta manera puedes usarlo así:

 MyArray_t my_array; worker w; w.parr_ = &arr; w.doStuff(); 

Como podemos ver, no es necesario establecer explícitamente un segundo parámetro. Tal vez sea útil para alguien.