Tengo dos clases base con cláusulas de uso
class MultiCmdQueueCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
class PlcMsgFactoryImplCallback {
using NetworkPacket = Networking::NetworkPacket;
....
}
Entonces declaro una clase
class PlcNetwork :
public RouterCallback,
public PlcMsgFactoryImplCallback,
public MultiCmdQueueCallback {
private:
void sendNetworkPacket(const NetworkPacket &pdu);
}
el compilador marca una referencia de error a 'NetworkPacket' es ambiguo 'sendNetworkPacket (NetworkPacket & ...'
Ahora ambas 'cláusulas de uso' se resuelven en la misma clase subyacente Redes: NetworkPacket
y de hecho si reemplazo la declaración del método con:
void sendNetworkPacket(const Networking::NetworkPacket &pdu);
Se compila bien.
¿Por qué el compilador trata cada cláusula de uso como un tipo distinto a pesar de que ambos apuntan al mismo tipo subyacente? ¿Es obligatorio por el estándar o tenemos un error de compilación?
c++
using-declaration
Andrew Goedhart
fuente
fuente
NetworkPacket
: en MultiCmdQueueCallback, en PlcMsgFactoryImplCallback, en Networking. Cuál debe usarse debe especificarse. Y no creo que ponervirtual
sea de ninguna ayuda aquí.Respuestas:
Antes de ver el tipo de alias resultante, (y accesibilidad)
nos fijamos en los nombres
y de hecho,
NetworkPacket
puede serMultiCmdQueueCallback::NetworkPacket
PlcMsgFactoryImplCallback::NetworkPacket
El hecho de que ambos apuntan
Networking::NetworkPacket
es irrelevante.Hacemos la resolución del primer nombre, lo que resulta en ambigüedad.
fuente
error: [...] is private within this context
.class A { public: void f(char, int) { } private: void f(int, char) { } }; void demo() { A a; a.f('a', 'd'); }
- no es lo mismo, pero la resolución de sobrecarga funciona igual: considere todas las funciones disponibles, solo después de seleccionar la apropiada considere la accesibilidad ... En el caso dado, también obtiene ambigüedad; si cambia la función privat para aceptar dos caracteres, se seleccionará aunque sea privada y se encontrará con el siguiente error de compilación.Simplemente puede resolver la ambigüedad seleccionando manualmente cuál desea usar.
El compilador solo busca las definiciones en las clases base. Si el mismo tipo y / o alias está presente en ambas clases base, simplemente se queja de que no sabe cuál usar. No importa si el tipo resultante es el mismo o no.
El compilador solo busca nombres en el primer paso, totalmente independientes si este nombre es una función, tipo, alias, método o lo que sea. Si los nombres son ambiguos, ¡no se realiza ninguna otra acción desde el compilador! Simplemente se queja con el mensaje de error y se detiene. Entonces, simplemente resuelva la ambigüedad con la declaración de uso dada.
fuente
De los documentos :
Aunque esas dos
using
cláusulas representan el mismo tipo, el compilador tiene dos opciones en la siguiente situación:Puede elegir entre:
MultiCmdQueueCallback::NetworkPacket
yPlcMsgFactoryImplCallback::NetworkPacket
porque hereda de ambas
MultiCmdQueueCallback
y dePlcMsgFactoryImplCallback
las clases base. Un resultado de la resolución del nombre del compilador es el error de ambigüedad que tiene. Para solucionar esto, debe indicar explícitamente al compilador que use uno u otro de esta manera:o
fuente
class C { void f(uint32_t); }; void C::f(unsigned int) { }
(siempre que el alias coincida). Entonces, ¿por qué hay una diferencia aquí? Todavía son del mismo tipo, confirmado por su cita (que no considero suficiente para explicar) ...class C : public A, public B { void f(A::D); }; void C::f(B::D) { }
- al menos GCC acepta.Hay dos errores:
privado-privado
No veo un problema de que el compilador se queje del segundo problema primero porque el orden realmente no importa: debe solucionar ambos problemas para continuar.
público-público
Si cambia la visibilidad de ambos,
MultiCmdQueueCallback::NetworkPacket
yaPlcMsgFactoryImplCallback::NetworkPacket
sea pública o protegida, entonces el segundo problema (ambigüedad) es obvio: esos son dos alias de tipo diferente, aunque tienen el mismo tipo de datos subyacente. Algunos pueden pensar que un compilador "inteligente" puede resolver esto (un caso específico) por usted, pero tenga en cuenta que el compilador necesita "pensar en general" y tomar decisiones basadas en reglas globales en lugar de hacer excepciones específicas de cada caso. Imagine el siguiente caso:¿Debería el compilador tratar a ambos por
NetworkPacketID
igual? Seguro que no. Porque en un sistema de 32 bits,size_t
tiene 32 bits de largo mientrasuint64_t
que siempre es de 64 bits. Pero si queremos que el compilador verifique los tipos de datos subyacentes, entonces no podría distinguirlos en un sistema de 64 bits.publico privado
Creo que este ejemplo no tiene ningún sentido en el caso de uso de OP, pero dado que aquí estamos resolviendo problemas en general, consideremos que:
Creo que en este caso el compilador debe tratar
PlcNetwork::NetworkPacket
comoPlcMsgFactoryImplCallback::NetworkPacket
porque no tiene otros Oferta de. Por qué todavía se niega a hacerlo y culpa a la ambigüedad es un misterio para mí.fuente