¿Por qué predeterminado argumentos de plantilla sólo se permite en las plantillas de clase? ¿Por qué no podemos definir un tipo predeterminado en un miembro de la plantilla de función? Por ejemplo:

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

Lugar, C++ fuerzas que la plantilla predeterminada argumentos sólo se permite en una plantilla de clase.

  • +1 lo Que realmente es una pregunta muy difícil.
  • Para las tres primeras respuestas publicadas, considere este ejemplo: struct S { template <class R = int> R get_me_R() { return R(); } }; El parámetro de plantilla no puede deducirse del contexto.
  • Buena pregunta. 3 personas ya han respondido a decir que «no tiene sentido», y todos están mal en general. Función de los parámetros de la plantilla no siempre son deducibles de la función de los parámetros de llamada. Por ejemplo, si se les permitía podría escribir template <int N = 1> int &increment(int &i) { i += N; return i; } y, a continuación, increment(i); o increment<2>(i);. Como es, tengo que escribir increment<1>(i);.
  • En realidad, la mía y la de AraK ejemplos pueden ser tratados por la sobrecarga. litb que no se debe, creo yo, porque el parámetro de plantilla puede ser deducido o podría ser especificada.
  • hmm puede escribir template<typename Iterator> void sort(Iterator beg, Iterator end) { sort(beg, end, std::less<Iterator>()); } y escribe los tres-args como una sobrecarga. Creo que ha hecho de esa manera en el día de hoy std::sort. (aww, yo debería haber pasado value_type a std::menos xD)
  • std::ordenación se realiza de esa manera ahora, pero su definición, algo que la actual definición de no – especificar 2 (de 2) los parámetros de la plantilla, pero sólo 2 (de 3) argumentos de llamada de función. Pero yo se pensaba equivocadamente que significa que su ejemplo no se puede hacer con sobrecargas, en realidad, simplemente no está hecho con sobrecargas en la actualidad desde el 2-plantilla-param sobrecarga no tiene un valor por defecto para el 3 de param. El ejemplo en el informe de defecto se puede hacer con sobrecargas (he comprobado, la búsqueda de una falta ; en el texto de ejemplo en el proceso).
  • El punto y coma que falta es en realidad un nuevo EOL sobrecarga de operadores para complementar B. Stavtrup de la «Sobrecarga de C++ espacio en Blanco», publicado en el Diario de la Programación Orientada a Objetos, el 1 de abril de 1992. (www2.research.att.com/~bs/papers.html)

InformationsquelleAutor Arman | 2010-03-15

5 Comentarios

  1. 146

    Tiene sentido dar la plantilla por defecto de los argumentos. Por ejemplo, usted podría crear una especie de funció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 introduce a C++. Ver este informe de defecto por Bjarne Stroustrup: Plantilla predeterminada Argumentos para la Función de las Plantillas y lo que él dice

    La prohibición de la plantilla por defecto de los argumentos para la función de las plantillas no es una desafortunada remanente de la época, que independiente de las funciones fueron tratados como ciudadanos de segunda clase, y requirió que todos los argumentos de plantilla para ser deducida a partir de los argumentos de la función, en lugar de lo especificado.

    La restricción obstaculiza seriamente el estilo de programación innecesariamente decisiones independientes de funciones distintas de las funciones miembro, por lo que es más difícil escribir STL-código de estilo.

    • ¿Hay algún tipo de vínculo con esa información?
    • el informe de defecto enlace contiene los cambios que se realizan en el proyecto de trabajo para C++0x y las discusiones. Argumentos ni deduce ni se especifica explícitamente se obtienen a partir de argumentos predeterminados. GCC4.4 admite argumentos predeterminados de la función de las plantillas en C++0x modo.
    • Nada que ver con la pregunta o la respuesta, pero Herb Sutter llamado la upcomming estándar C++11 después de la última reunión de los sábados. Acabo de leer hoy y apetece compartir 🙂 herbsutter.wordpress.com/2010/03/13/…
    • y la obligada pregunta de seguimiento… cuando se espera para hacer su camino en otros compiladores 🙂
    • Yo tenía el mismo problema: no hay posibilidad de speficy el tipo predeterminado en función de la plantilla. Yo lo he solucionado con un explícito de la creación de instancias de la función en el tipo por defecto (double en mi caso). Tal vez no es «general», pero ¿hay algún inconveniente con esta práctica? Gracias.
    • El siguiente código de falla al compilar, con errores como error: invalid conversion from ‘int’ to ‘int*’, alguna idea de por qué: ` #include <matriz> #include <algoritmo> #include <funcional> plantilla<nombre del Iterador, typename Comp = std::menos<Iterator> > void my_sort(Iterator inicio, Iterator end, Comp c = Comp()) { std::sort(inicio, final, c); } int main() { std::array<int, 5> ar{5,2,21,7,4}; my_sort(ar.begin(), ar.end()); } `
    • por favor, hacer una nueva pregunta de stackoverflow para que. el error del compilador en ese fragmento es ortogonal a esta pregunta me respondió.
    • mientras que usted es técnicamente correcto, la mayoría de los tipos no comparar a los iteradores, pero en lugar de los valores señalados por los iteradores. El cambio de std::less<Iterator> a std::less<typename std::iterator_traits<Iterator>::value_type> corrige el problema.
    • ah lo siento no me he dado cuenta que el código que me dio fue en parte el código de mi respuesta. Por supuesto, hubo un error técnico en mi código. Fijo
    • El uso de C++ moderno de la plantilla de encabezado puede ser simplificado a sólo template<typename Iterator, typename Comp = std::less<>>.
    • Su respuesta válida todavía con C++11 C++14 o C++17?

  2. 35

    Citar las Plantillas de C++: La Guía Completa (página 207):

    Cuando las plantillas se agregó originalmente para el lenguaje C++, función explícita de la plantilla de argumentos no eran una validez de constructo. La función de argumentos de plantilla siempre tenía que ser deducible a partir de la llamada de expresión. Como resultado, no parecía haber ninguna razón de peso para permitir la función predeterminada de la plantilla de argumentos debido a que por defecto siempre será reemplazado por el valor deducido.

    • simple y conciso 🙂
  3. 17

    Hasta ahora, todos los que ofreció ejemplos de plantilla por defecto de los parámetros para la función de las plantillas se puede 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 propia:

    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 he demostrado 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 las observaciones para cada llamada a f, y la comentada llamada no puede compilar como se esperaba.

    Por lo que sospecho que por defecto los parámetros de la plantilla «no son necesarios», pero probablemente sólo en el mismo sentido que la función predeterminada argumentos «no son necesarios». Como Stroustrup defecto del informe indica, además de no deducir los parámetros era demasiado tarde para cualquier persona para que se de cuenta y/o realmente aprecio que hizo valores predeterminados útil. Así que la situación actual es, en efecto, basado en una versión de la función de las plantillas que nunca fue estándar.

    • Así que el huevo era correr más rápido que el pollo?:) interesante. Gracias.
    • Probablemente, sólo una de esas cosas. El C++ proceso de normalización lento, en parte, por lo que la gente tiene tiempo para darse cuenta de que un cambio crea oportunidades o dificultades en otros lugares en el estándar. Dificultades con suerte son atrapados por las personas de implementar el proyecto de norma a medida que avanzan, cuando un punto contradicción o ambigüedad. Oportunidades para permitir a cosas que no estaban permitidas antes de, confiar en alguien que quiere escribir el código de cuenta de que ya no necesita ser ilegal…
    • Uno más, para ti: template<typename T = void> int SomeFunction();. El parámetro de plantilla aquí no se usa nunca, y de hecho la función nunca es llamado; el único lugar en el que se conoce está en una decltype o sizeof. El nombre deliberadamente coincide con el nombre de otra función, pero el hecho de que es una plantilla significa que el compilador se prefiere la función libre, si es que existe. Los dos se utilizan en SFINAE para proporcionar el comportamiento por defecto, donde la definición de una función es la que falta.
  4. 4

    En Windows, con todas las versiones de Visual Studio, puede convertir este error (C4519) a una advertencia o desactivar la función así:

    #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í.

    • Tenga en cuenta que, aunque esta deshabilitar la «plantilla predeterminada argumentos sólo se permite en una plantilla de clase» del mensaje, que en realidad no hacer la plantilla de creación de instancias de proceso con el valor proporcionado. Que requiere VS2013 (o cualquier otro compilador que ha completado C++11 defecto 226 «plantilla Predeterminada argumentos para la función de las plantillas»)
  5. 1

    Lo que yo uso es el siguiente truco:

    Digamos que usted desea tener la función como esta:

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

    Usted no será permitido, pero no tengo manera siguiente:

    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í de esta manera usted puede utilizarlo como este:

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

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

    • Este definitivamente no es una respuesta.
    • puede usted explicar por qué? No estamos todos de plantillas de C++ gurús. Gracias.
    • Se trata de una solución que es bastante limpio pero no cubre todos los casos que usted podría desear. Por ejemplo, ¿cómo podría aplicar esto a un constructor?
    • si he entendido correctamente, entonces usted puede hacer así: plantilla <typename E, typename ARR_E> trabajador<E, ARR_E>::trabajador(ARR_E* parr) { parr_ = parr; }. Y, a continuación, utilizarlo como este: trabajador<int> w2(&mi_matriz);

Dejar respuesta

Please enter your comment!
Please enter your name here