C ++ efectiva del artículo 42: (typenam entender el doble sentido de) plantillas y programación genérica de

En primer lugar, la importancia de ①

  • Significado ①: nombretipo puede declarar tipos en el parámetro de plantilla
  • Cuando el tipo declarado de la plantilla de parámetros, plantilla y clase son equivalentes , tanto puede haber
  • Por ejemplo:
//两者是等价的
template<class T> class Widget;
template<typename T> class Widget;

En segundo lugar, la importancia ②

  • Significado ②: Se puede utilizar para declarar un tipo determinado

espectáculos de demostración

  • Ahora tenemos una plantilla que acepta un tipo de contenedor STL, y luego imprimir el valor del recipiente en el segundo elemento, pero esta plantilla puede generar errores. Código es el siguiente:
template<typename C>
void print2nd(const C& container)
{
    if (container.size() >= 2) {
        C::const_iterator iter(container.begin()); //初始化迭代器,绑定到第一个元素上
        ++iter;
        int value = *iter;
        std::cout << value;
    }
}
  • Acerca de "nombre de esclavo anidados" y "nombre no esclavo" concepto:
    • nombre de esclavo:
      • Por lo anterior iter, su recipiente es un const_iterator tipo iterador contenedor, que depende del tipo de plantilla parámetro C, así que llamamos const_iterator como un nombre secundario (es decir: un nombre dentro de la plantilla depende de una plantilla de parámetros de por lo que es un nombre de esclavo)
      • Cuando un nombre de esclavo pertenece a la clase, que llamamos el nombre del dependiente anidada. Así, el anterior es un nombre const_iterator dependiente anidada
    • No subordinada Nombre: La variable de valor por encima de cuyo tipo es int, no depende de ninguna otra cosa, así que llamamos a nombre int no dependiente
  • La razón por la cual el código anterior puede producir errores asociados con el nombre de esclavo. Ahora consideramos una situación de este tipo:
    • Print2nd modificamos la plantilla, se supone que define un puntero a la iterador, como sigue
    • Sin embargo, el compilador podría interpretar de esta manera: no const_iterator un nombre de esclavo anidada, sino una especie de variables miembro estáticas, x es una variable local. El siguiente código para que el compilador se puede considerar que multiplicarse por dos variables
template<typename C>
void print2nd(const C& container)
{
    //...
    //const_iterator可能被编译器理解为C的static成员变量,x为一个变量,下面是两个变量的相乘
    C::const_iterator* x;
    //...
}
  • El enfoque correcto se anida el nombre del dependiente con un nombre de tipo de palabras clave, por lo que puede indicar explícitamente al compilador es un tipo de algo, en lugar de otras cosas. Código es el siguiente:
template<typename C>
void print2nd(const C& container)
{
    if (container.size() >= 2) {
        //使用typename,显式告诉编译器,const_iterator是一个类型
        typename C::const_iterator iter(container.begin());
        ++iter;
        int value = *iter;
        std::cout << value;
    }
}
  • Con las reglas anteriores y luego se podría escribir la siguiente función de plantilla que acepta unas clases de contenedores, iteradores y el contenedor como un parámetro. Código es el siguiente:
template<typename C>
void print2nd(const C& container,typename C::const_iterator iter)
{
    //...
}

Una excepción de nombretipo

  • Cuando nombretipo utiliza para declarar el tipo, no puede estar en dos lugares:
    • ① lista de clase base derivada
    • ② columna inicialización miembro en el constructor
  • Asumimos un tipo anidado en la clase base . Por ejemplo:
template<typename T>
class Derived :public Base<T>::Nested //此处不可以使用typename
{
public:
    explicit Derived(int) 
        :Base<T>::Nested(x)//此处不可以使用typename
    {
        typename Base<T>::Nested temp; //此处可以使用typename
    }
};

rasgos TypeName mecanismos utilizados en

  • Supongamos ahora tenemos una función de plantilla que acepta un tipo de iterador, tenemos la intención de objetivo en la función conocida como iteradores hacen una copia. Código es el siguiente:
template<typename IterT>
void workWithIterator(IterT iter)
{
    typename std::iterator_traits<IterT>::value_type temp(*iter);
    //...
}
  • Aquí se utiliza a iterator_traits <> plantilla de clase, de hecho, un tipo de clases de rasgos (véase la cláusula 47). Pasamos a la clase de iterador tipo para un instanciado, entonces podemos extraer fuera del recipiente a través del cual el value_type iterador refiere. Por ejemplo:
    • Si IterT es una lista <cadena> :: iterador, entonces VALUE_TYPE en nombre de la cadena, la temperatura es del tipo de cadena
    • Si IterT es un vector <int> :: iterador, a continuación, en VALUE_TYPE int nombre, tipo de temperatura es de tipo int
  • Debido value_type es un tipo incorporado, por lo que necesitamos para usar nombretipo comunicado que es un tipo
  • Si el código es más complejo, entonces podemos también ser utilizado con un typedef. Por ejemplo:
template<typename IterT>
void workWithIterator(IterT iter)
{
    typename std::iterator_traits<IterT>::value_type value_type; //为类型声明别名
    value_type temp(*iter); //使用类型定义变量
    //...
}
  • Sobre los problemas de portabilidad de nombretipo: Algunos compiladores aceptan el nombre de tipo, pero puede haber algunos compilador no aceptará nombretipo. Por lo tanto existe la portabilidad

En tercer lugar, el resumen

  • Cuando se declara un parámetro de plantilla, prefijar la clase de palabras clave y nombre de tipo son intercambiables
  • Use palabras clave TYPENAME anidada nombre de identificación de tipo dependiente; listas, pero no en la clase base (il columna Class) o inicialización miembro dentro de la lista (un miembro de la columna de valor inicial) a ella como un modificador de la clase base
Liberadas 1525 artículos originales · ganado elogios 1084 · Vistas de 450.000 +

Supongo que te gusta

Origin blog.csdn.net/qq_41453285/article/details/104850604
Recomendado
Clasificación