Argumentos de plantilla predeterminados para las plantillas de función


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

struct mycclass {
  template<class T=int>
  void mymember(T* vec) {
    // ...
  }
};

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

 179
Author: Luc Danton, 2010-03-15

5 answers

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

template<typename Iterator, 
         typename Comp = std::less<
            typename std::iterator_traits<Iterator>::value_type> >
void sort(Iterator beg, Iterator end, Comp c = Comp()) {
  ...
}

C++0x les introduce en 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 función es un remanente erróneo de la época en que las funciones independientes se trataban como ciudadanos de segunda clase y requerían toda la plantilla argumentos a ser deducidos de los argumentos de la función en lugar de especificados.

La restricción restringe seriamente el estilo de programación al hacer innecesariamente que las funciones independientes sean diferentes de las funciones miembro, lo que dificulta la escritura de código de estilo STL.

 143
Author: Johannes Schaub - litb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-10 21:32:13

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 eran una construcción válida. Los argumentos de la plantilla de función siempre tenían que ser deducibles de la expresión de la llamada. Como resultado, no parecía haber ninguna razón convincente para permitir argumentos de plantilla de función por defecto, ya que el valor por defecto siempre sería anulado por el valor deducido.

 34
Author: James McNellis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-15 13:48:21

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 <class R = int> R get_me_R() { return R(); } 
};

Podría ser:

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

Mi propio:

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

Podría ser:

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

Litb:

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

Podría ser:

template<typename Iterator>
void sort(Iterator beg, Iterator end, std::less<Iterator> c = std::less<Iterator>())

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

Stroustrup:

template <class T, class U = double>
void f(T t = 0, U u = 0);

Podría ser:

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

Que probé con el siguiente código:

#include <iostream>
#include <string>
#include <sstream>
#include <ctype.h>

template <typename T> 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 <typename S, typename T> void g(S s, T t){
    std::cout << "f<" << typeid(S).name() << "," << typeid(T).name()
        << ">(" << s << "," << prettify(t) << ")\n";
}


template <typename S, typename T> void f(S s = 0, T t = 0){
    g<S,T>(s,t);
}

template <typename S> void f(S s = 0, double t = 0) {
    g<S,double>(s, t);
}

int main() {
        f(1, 'c');         // f<int,char>(1,'c')
        f(1);              // f<int,double>(1,0)
//        f();               // error: T cannot be deduced
        f<int>();          // f<int,double>(0,0)
        f<int,char>();     // f<int,char>(0,0)
}

La salida impresa coincide con los comentarios de cada llamada a f, y la llamada comentada no se compila como se esperaba.

Así que sospecho que los parámetros de plantilla predeterminados "no son necesarios", pero probablemente solo en el mismo sentido que los argumentos de función predeterminados "no son necesarios". Como indica el informe de defectos de Stroustrup, la adición de parámetros no deducidos era demasiado tarde para que cualquiera se diera cuenta y/o apreciara realmente que hacía útiles los valores predeterminados. Por lo tanto, la situación actual se basa en una versión de plantillas de funciones que nunca fue estándar.

 17
Author: Steve Jessop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-15 14:46:01

En Windows, con todas las versiones de Visual Studio puede convertir este error ( C4519) en una advertencia o deshabilitarlo de la siguiente 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í.

 4
Author: Adi Shavit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-09 08:19:04

Lo que uso es el siguiente truco:

Digamos que quieres tener una función como esta:

template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array)
{
    E one(1);
    array.add( one );
}

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

template <typename T>
struct MyArray_t {
void add(T i) 
{
    // ...
}
};

template <typename E, typename ARR_E = MyArray_t<E> >
class worker {
public:
    /*static - as you wish */ ARR_E* parr_;
    void doStuff(); /* do not make this one static also, MSVC complains */
};

template <typename E, typename ARR_E>
void worker<E, ARR_E>::doStuff()
{
    E one(1);
    parr_->add( one );
}

Así que de esta manera puedes usarlo de esta manera:

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

Como podemos ver no hay necesidad de establecer explícitamente el segundo parámetro. Tal vez sea útil para alguien.

 1
Author: alariq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-14 22:28:52