c++ - para - que es using namespace std en programacion
¿Por qué el estándar de C++ especifica que los nombres no calificados en una plantilla no son dependientes? (3)
Creo que es una cuestión de consistencia. Considera esto, un ejemplo un poco modificado:
archivo de cabecera:
template<typename T>
class Base
{
public:
T x;
};
extern int x;
template<typename T>
class C : public Base<T>
{
public:
bool m() { return x == 0; }
};
y archivo fuente:
template<>
class Base<int> // but could be anything
{
public:
// no x here
};
int main()
{
C<char> c1;
c1.m(); // may select ::x or Base<char>::x
C<int> c2;
c2.m(); // has only one choice: ::x
return(0);
}
La redacción en la norma garantiza que el compilador producirá un error o seleccionará el símbolo que vea en el punto de definición de la plantilla. Si el compilador debía diferir la resolución de nombres a la creación de instancias de la plantilla, puede seleccionar diferentes objetos visibles en este punto y lo que puede sorprender al desarrollador.
Si el desarrollador QUIERE acceder al nombre del dependiente, debe indicarlo explícitamente y no debe ser tomado por sorpresa.
También tenga en cuenta que si la x no estuviera disponible en el punto de definición de la plantilla, el siguiente código se rompería (inesperadamente) una regla de definición:
one.cpp
#include <template_header>
namespace {
int x;
}
void f1()
{
C<int> c1;
}
two.cpp
#include <template_header>
namespace {
char x;
}
void f2()
{
C<int> c2;
}
Se podría esperar que las variables c1 y c2 sean del mismo tipo y, por ejemplo, se puedan pasar con seguridad dos funciones C<int> const &
toman el parámetro C<int> const &
, pero básicamente las dos variables tienen el mismo nombre de tipo pero las implementaciones son diferentes.
¿Por qué es que el estándar de C ++ especifica que los nombres no calificados en una plantilla no son dependientes?
p.ej
template<typename T>
class Base
{
public:
T x;
};
template<typename T>
class C : public Base<T>
{
public:
bool m() { return x == 0; } // Error: undeclared identifier ''x''
};
Citando la respuesta aceptada a una question SO sobre cómo superar la restricción:
El estándar especifica que los nombres no calificados en una plantilla no son dependientes y se deben buscar cuando se define la plantilla. La definición de una clase base dependiente es desconocida en ese momento (pueden existir especializaciones de la plantilla de clase base), por lo que los nombres no calificados no se pueden resolver.
Sin embargo, las respuestas citadas y otras respuestas no especifican por qué esto es lo que especifica la norma. ¿Cuál es la razón de esta restricción?
Esto no es exactamente lo que realmente dice la norma. Lo que realmente dice es que las clases base dependientes no se examinan durante la búsqueda de nombre no calificado. Por supuesto, un nombre no calificado puede ser dependiente dado el contexto correcto; así es como funciona ADL en las plantillas: dado un parámetro de tipo de plantilla T
, foo
en foo(T())
es un nombre dependiente.
En cualquier caso, la razón por la que no puede hacer este tipo de búsqueda es directa: en el momento de la definición de la plantilla, no tiene idea de qué aspecto tendrá la clase base dependiente, gracias a las especializaciones que se incluirán más adelante, por lo que puede No hagas ninguna búsqueda significativa. Cada identificador mal escrito en una plantilla con una clase base dependiente no se puede diagnosticar hasta que se crea una instancia, si es que se crea una instancia. Y dado que cada identificador no calificado podría haber sido de una clase base dependiente, necesitará alguna forma de responder "¿es este un tipo?" y "¿es esto una plantilla?", ya que las respuestas a esas preguntas afectan el análisis. Eso significa algo así como el temido nombre de typename
clave y template
palabras clave de la template
, pero en muchos más lugares.
Ya sea compatible con el estándar o no, en Visual Studio 2015, esto no es un problema en absoluto. Además, a pesar del comentario de Tomek, el compilador toma la x correcta.
static int x = 42;
template<typename T>
class Base {
public:
T x;
Base() { x = 43; }
};
template<>
class Base<int> { };
template<typename T>
class C :public Base<T>
{
public:
int m() { return x; }
};
void main() {
C<int> cint;
C<char> cchar;
std::cout << "cint: " << cint.m() << std::endl;
std::cout << "cchar: " << cchar.m() << std::endl;
}
// Output is:
// cint: 42
// cchar: 43