No entiendo cómo este pedazo de código (de Wikipedia) obras:

template <int N>
struct Factorial 
{
    enum { value = N * Factorial<N - 1>::value };
};

template <>
struct Factorial<0> 
{
    enum { value = 1 };
};

//Factorial<4>::value == 24
//Factorial<0>::value == 1
void foo()
{
    int x = Factorial<4>::value; //== 24
    int y = Factorial<0>::value; //== 1
}
  • ¿Qué es esta extraña plantilla que
    toma <int N>?
  • ¿Qué es esto segundo
    extraño plantilla <>?
  • ¿Cuáles son los
    enumraciones para?
  • ¿Cuál es la ventaja
    de usar este en lugar de lo normal
    tiempo de ejecución factorial de cálculo?
  • ¿Con que frecuencia hace uso de la gente de esto? He estado usando C++ por un tiempo ahora, pero nunca antes. Cómo gran parte de C++ estaba perdiendo?

Gracias!

InformationsquelleAutor Lazer | 2010-06-21

5 Comentarios

  1. 24
    • ¿Qué es esta extraña plantilla que necesita <int N>?

    En C++, la plantilla de los argumentos pueden ser de los tipos (con el prefijo class o typename) o enteros (con el prefijo int o unsigned int). Aquí estamos en el segundo caso.

    • ¿Qué es esta segunda extraño template <>?

    template<> struct Factorial<0> es una completa especialización de Factorial plantilla de clase, lo que significa que 0 se considera un valor especial a la que corresponde su propia versión de Factorial.

    • ¿Cuáles son las enumeraciones para?

    las enumeraciones son la manera de calcular los valores en la metaprogramación C++

    • ¿Cuál es la ventaja de usar este en lugar de lo normal en tiempo de ejecución factorial de cálculo?

    La razón por la que este código fue creado en el primer lugar es para crear una prueba de concepto de que el cálculo se puede hacer uso de la metaprogramación. La ventaja es que el código generado es muy eficiente (llamando Factorial<4>::value es equivalente a simplemente escribir «24» en el código.

    • ¿Con que frecuencia hace uso de la gente de esto? He estado usando C++ por un tiempo ahora, pero nunca antes. Cómo gran parte de C++ estaba perdiendo?

    De dicha funcionalidad es raramente alcanzada usando este método, pero la metaprogramación es la más utilizada hoy en día. Ver Impulsar la meta-programación de la biblioteca para obtener una sugerencia de lo que puede hacerse.

    • No-tipo de los parámetros de la plantilla no se limitan a los números enteros. Pueden ser integrales o enumeración de tipo puntero a objeto o un puntero a función, la referencia a objeto o una referencia a una función o un puntero a miembro.
    • No sé mucho acerca de las plantillas, pero no debería ser template <0> struct Factorial en lugar de template <> struct Factorial<0> en el segundo caso?
    • También, ¿cuál es el uso de enum la forma en que se utiliza?
    • Tipo <strike>argumentos</strike> parámetros no pueden ser precedidos por struct. De hacerlo así se declare un no-tipo de parámetro: template<struct A> struct H { }; está mal formado debido a la no-tipo de parámetro es de la clase de tipo.
    • Samuel: Usted se olvidó de plantillas. Hay plantilla plantilla de argumentos.
    • No, template <> struct Factorial<0> realmente es la sintaxis correcta. No hay más explicación, esto es sólo la forma en que la sintaxis para una especialización fue especificado.
    • «la llamada Factorial<4>::el valor es equivalente a la llamada a una función que devuelve simplemente de 24» en Realidad tiene incluso menos sobrecarga que una llamada a una función. Es equivalente a usar un valor de enumeración que se ha definido para ser de 24, que es básicamente equivalente a la escritura int value = 24; directamente.
    • He quitado el código de formato y lo hizo comillas en lugar de ello, lo que parece más fácil de leer para mí. Espero que está bien con usted.
    • Benoit, usted realmente debe fijar cuál es permitido para los parámetros – ver §14.1/4. También, como sepp2k sugerencias, un enum es un constante en tiempo de compilación y, como tal, muy diferente a la de una llamada de función.
    • ¿Cómo es posible que 2 estructuras con idéntico nombre puede establecer, sin ningún error de compilación?
    • puede que desee echar un vistazo a la Sustitución de error no es un error (SFINAE)
    • Tu error está en pensar que hay son dos estructuras. De hecho, hay sólo uno, o muchos el potencial de las estructuras (uno para cada una de las int valor), dependiendo de cómo se mire (en realidad, no es una plantilla, con muchas posibles casos de la misma). Todos sino uno de los muchos posibles estructuras se define por la definición de plantilla en int n; uno de ellos es una explícita la especialización de la plantilla para el caso de n == 0. Cualquier momento plantillas de involucrarse tiene muchos (a menudo teóricamente infinito) estructuras con el mismo nombre; es por eso que C++ nombre-planchado de que es mucho más complejo de lo que C.

  2. 6

    ¿Qué es esta extraña plantilla que necesita
    <int N>?

    Una plantilla de declaración puede ser hecha en clases/tipos, en los valores y en los punteros. No se suelen ver de esta forma como la definición de las plantillas rara vez se utiliza constantes en los parámetros de la plantilla.

    ¿Qué es esta segunda extraño plantilla <>?

    La mejor manera de pensar de una plantilla es hacer algo similar a lo que el compilador hace: considere la posibilidad de la plantilla como de la clase, donde se sustituye el parámetro de plantilla con un valor real de ese tipo.

    Que es, para:

    template <int N>
    struct Factorial 
    {
        enum { value = N * Factorial<N - 1>::value };
    };

    Factorial<2>::value es equivalente a:

    //generated by the compiler when Factorial<2>::value is encountered in code:
    struct Factorial2 { enum { value = 2 * Factorial1::value }; };
    struct Factorial1 { enum { value = 1 * Factorial0::value }; };
    //not generated by compiler, as it was explicitly defined in the code you ask about:
    template <> struct Factorial<0> { enum { value = 1 }; }; //defines Factorial<0>

    ¿Cuáles son las enumeraciones para?

    Que definir una enumeración con una constante de value en tiempo de compilación, permitiendo a escribir el código de cliente como el de tu ejemplo.

    ¿Cuál es la ventaja de usar este
    en lugar de lo normal en tiempo de ejecución factorial
    cálculo?

    La ventaja es la eficiencia. Puesto que el valor de cálculo se expande en la compilación, el costo de tiempo de ejecución de Factorial<10>::value es el mismo Factorial<1>::valor. En el código compilado, ambos son constantes. Si se va a calcular un factorial en el rendimiento de código crítico y se conocía en tiempo de compilación que valor es, usted debe hacer esto, o calcular fuera de línea y definir una constante con el valor precalculado en el código.

    ¿Con que frecuencia hace uso de la gente de esto?

    Es el «esto» se refiere al cálculo recursivo de una constante? Si es así, no muy a menudo.

    Es el «este» de la definición de constantes en las plantillas? Muy a menudo 🙂

    Es el «este» de la particularización de una plantilla para un tipo específico? Muy muy muy a menudo. He comprendido que el std::vector tiene una completamente independiente de la implementación en algunos STL implementaciones (un std::vector<bool> con 8 elementos, no debería necesitar más de 1 byte para almacenar los valores).

    He estado usando C++ por un tiempo ahora,
    pero nunca antes. Cómo de grande
    parte de C++ estaba perdiendo?

    No necesariamente una gran parte. Si utiliza boost, es probable que el código que se utiliza es implementado usando cosas como esta.

    • La multiplicación es todavía ejecutan en tiempo de ejecución. Sólo la preparación de la operación se hizo en tiempo de compilación.
  3. 4

    He encontrado esta respuesta por Johannes Schaub – litb en una pregunta muy útil.

    [ Estoy copiar pegar la respuesta aquí, suponiendo que Johannes está bien con él. Voy a quitar la pasta si no le gusta ]


    Sí, no es un parámetro de tipo. Usted puede tener varios tipos de parámetros de plantilla

    • Tipo De Parámetros.
      • Tipos
      • Plantillas (sólo clases, funciones)
    • No-tipo de Parámetros
      • Punteros
      • Referencias
      • Integral expresiones constantes

    Lo que usted tiene no es de la última clase. Es una compilación de constante de tiempo (llamado constante de la expresión) y es de tipo entero o enumeración. Después de buscar en la norma, he tenido que mover las plantillas de clase en la sección de tipos, aunque las plantillas no son tipos. Pero se llama de tipo-parámetros para el propósito de describir los tipos, no obstante. Usted puede tener punteros (y también miembro de punteros), y las referencias a objetos/funciones que tienen vinculación externa (aquellos que pueden ser enlazado desde otros archivos objeto y cuya dirección es única en todo el programa). Ejemplos:

    Plantilla de tipo de parámetro:

    template<typename T>
    struct Container {
        T t;
    };
    
    //pass type "long" as argument.
    Container<long> test;

    Plantilla parámetro entero:

    template<unsigned int S>
    struct Vector {
        unsigned char bytes[S];
    };
    
    //pass 3 as argument.
    Vector<3> test;

    Plantilla parámetro de puntero (pasando un puntero a una función)

    template<void (*F)()>
    struct FunctionWrapper {
        static void call_it() { F(); }
    };
    
    //pass address of function do_it as argument.
    void do_it() { }
    FunctionWrapper<&do_it> test;

    Plantilla parámetro de referencia (pasando un entero)

    template<int &A>
    struct SillyExample {
        static void do_it() { A = 10; }
    };
    
    //pass flag as argument
    int flag;
    SillyExample<flag> test;

    Plantilla parámetro de plantilla.

    template<template<typename T> class AllocatePolicy>
    struct Pool {
        void allocate(size_t n) {
            int *p = AllocatePolicy<int>::allocate(n);
        }
    };
    
    //pass the template "allocator" as argument. 
    template<typename T>
    struct allocator { static T * allocate(size_t n) { return 0; } };
    Pool<allocator> test;

    Una plantilla sin ningún tipo de parámetros no es posible. Pero una plantilla sin ningún argumento explícito es posible – se ha predeterminado argumentos:

    template<unsigned int SIZE = 3>
    struct Vector {
        unsigned char buffer[SIZE];
    };
    
    Vector<> test;

    Sintácticamente, template<> está reservado para marcar un explícito de la plantilla de la especialización, en lugar de una plantilla sin parámetros:

    template<>
    struct Vector<3> {
        //alternative definition for SIZE == 3
    };

    • Si usted desea vincular a una relacionados con la respuesta, usa los comentarios para que. No basta con copiar/pegar la respuesta completa sin ningún tipo de adiciones por ti mismo.
  4. 3

    ¿Cuál es la ventaja de usar este en lugar de lo normal en tiempo de ejecución factorial de cálculo?

    Es más rápido – en teoría, el compilador se expanda el conjunto de plantillas en tiempo de compilación tal que Factorial<n>::value es simplemente una sola constante. En algunos infinitamente pequeño número de casos, que pueden hacer una gran diferencia.

    El lado negativo de esto es que tiene que ser calculado en tiempo de compilación, por lo que si su n se determina en tiempo de ejecución, entonces usted no puede usar ese método.

    ¿Con que frecuencia hace uso de la gente de esto? He estado usando C++ por un tiempo ahora,
    pero nunca antes. Cómo gran parte de C++ estaba perdiendo?

    Un caso como el que, a menudo no en todos. Plantilla de metaprogramación es potencialmente muy poderosa, pero el número de casos de este ejemplo es útil y lo suficientemente importante para el rendimiento son pequeñas.

    Pero es una técnica útil en C++, ya que permite el lenguaje para hacer una gran cantidad de potentes trucos que de otra manera estarían fuera de su alcance. Yo aventuro que es mucho más común de tomar ventaja de la plantilla de metaprogramación que alguien más ha hecho para usted – por ejemplo. Impulsar la usa mucho y puede hacer algunas cosas muy inteligente como resultado. Es potente, pero también puede ofuscar el código si no se hace bien.

  5. 2

    Es la recursividad realizadas por el compilador, donde

    template <>
    struct Factorial<0>
    {
    }

    es punto de salida de la recursividad.

    A primera Factorial<4> se ha resuelto. No hay especialización de Factorial por el valor de 4, por lo que la primera definición Factorial<> se utiliza.
    Su valor se calcula con Factorial<3>::value, donde el paso anterior se repite.

    Esto continuará, hasta que N==1, luego por la N-1, la especialización Factorial<0> entra en juego, donde el valor se establece en 1. La recursividad se detiene aquí y el compilador puede ir hacia arriba y calcula el resto de los valores de Factorial<N>.

Dejar respuesta

Please enter your comment!
Please enter your name here