c++ - subclase - la herencia es un modo de
Mover una función miembro de la clase base a la clase derivada rompe el programa sin ninguna razón obvia (4)
- ¿Por qué pasó esto?
Para la clase derivada,
B<T>
no es una clase base no dependiente, no se puede determinar sin conocer el argumento de la plantilla.
Y
bitset
es un nombre no dependiente, que no se buscará en la clase base dependiente.
En cambio,
std::bitset
se usa aquí (debido al
using namespace std;
de
using namespace std;
).
Entonces obtendrás:
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
Puede hacer que el nombre dependa de
bitset
;
porque los nombres dependientes solo se pueden buscar en el momento de la creación de instancias, y en ese momento se conocerá la especialización de base exacta que debe explorarse.
Por ejemplo:
return this->bitset < 32 // The mouth is not full of teeth
// ~~~~~~
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
o
return B<T>::bitset < 32 // The mouth is not full of teeth
// ~~~~~~
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
o
using B<T>::bitset;
return bitset < 32 // The mouth is not full of teeth
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
- ¿Cuál debería ser el título de esta pregunta después de haberla respondido?
"¿Cómo acceder a los nombres no dependientes en la clase base de plantilla?"
Esta pregunta (inventada) se formuló inicialmente como un rompecabezas, ocultando algunos de los detalles que podrían ayudar a ver el problema más rápido. Desplácese hacia abajo para MCVE versión más simple de MCVE .
Versión original (a-la puzzle)
Tengo este código que genera
0
:
#include <iostream>
#include <regex>
using namespace std;
regex sig_regex("[0-9]+");
bool oldmode = false;
template<class T>
struct B
{
T bitset;
explicit B(T flags) : bitset(flags) {}
bool foo(T n, string s)
{
return bitset < 32 // The mouth is not full of teeth
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
}
};
template<class T>
struct D : B<T>
{
D(T flags) : B<T>(flags) {}
};
int main()
{
D<uint64_t> d(128 | 16 | 1);
cout << d.foo(7, "123") << endl;
}
Sin embargo, cuando muevo la función
foo()
de
B
a
D
, comienza a generar
1
(la
prueba está en Coliru
).
¿Por qué pasó esto?
Versión MCVE
#include <iostream>
#include <bitset>
using namespace std;
template<class T>
struct B
{
T bitset{0};
bool foo(int x)
{
return bitset < 32 && 63 > (x + 1) == x % 2;
}
};
template<class T>
struct D : B<T>
{
bool bar(int x) // This is identical to B<T>::foo()
{
return bitset < 32 && 63 > (x + 1) == x % 2;
}
};
int main()
{
D<uint64_t> d;
cout << d.foo(1) << endl; // outputs 1
cout << d.bar(1) << endl; // outputs 0; So how is bar() different from foo()?
}
Es por eso que nunca debe
using namespace std;
bool foo(T n, string s)
{
return bitset < 32
&& 63 > (~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
Ese
bitset
no es lo que crees que es.
Debido a que
B<T>
es una clase base dependiente, los miembros están ocultos de la búsqueda no calificada.
Por lo tanto, para acceder al conjunto de
bitset
, debe acceder a él a través de
this
1
, o calificarlo explícitamente (consulte
here
para obtener más detalles):
(this->bitset)
B<T>::bitset
Debido a que
bitset
no nombra
B<T>::bitset
en el caso derivado, ¿qué podría significar?
Bueno, porque escribiste
using namespace std;
, en realidad es
std::bitset
, y el resto de su expresión resulta ser válido.
Esto es lo que pasa:
bool foo(T n, string s)
{
return std::bitset<32 && 63>(~n & 255) == oldmode
&& regex_match(s, sig_regex);
}
32 && 63
evalúa como
true
, que se promueve a
1u
para el argumento de plantilla
std::bitset
.
Este
std::bitset
se inicializa con
~n & 255
, y se verifica la igualdad con
oldmode
.
Este último paso es válido porque
std::bitset
tiene un constructor no explícito que permite construir un
std::bitset<1>
oldmode
desde el modo
oldmode
.
1
Tenga en cuenta que necesitamos paréntesis
this->bitset
en este caso debido a algunas reglas de desambiguación de análisis bastante sutiles.
Consulte El
miembro base dependiente de la plantilla no se resuelve correctamente
para obtener más detalles.
Este es un ejemplo genial !!! :)
Creo que lo que está sucediendo es esto:
bitset < 32 && 63 >(~n & 255)
Se analiza como construirme un
bitset
Sí, porque el conjunto de
bitset
se interpretará como un nombre no dependiente y hay una plantilla llamada
std::bitset<T>
, por lo tanto, se analizará como:
template<class T>
struct D : B<T>
{
D(T flags) : B<T>(flags) {}
bool foo(T n, string s)
{
return ((std::bitset < 32 && 63 > (~n & 255)) == oldmode)
&& regex_match(s, sig_regex);
}
};
Necesitas hacerlo así:
template<class T>
struct D : B<T>
{
D(T flags) : B<T>(flags) {}
bool foo(T n, string s)
{
// or return B<T>::bitset
return (this->B<T>::bitset < 32) // The mouth is not full of teeth
&& 63 > (~n & 255) == oldmode // Fooness holds
&& regex_match(s, sig_regex); // Signature matches
}
};
o mejor, no use el
using namespace std;