c++ - poo - Choque entre las funciones de C importadas en un espacio de nombres e importadas al espacio de nombres global
para que sirve el using namespace en poo en c++ (2)
En mi código, traigo los encabezados de OpenSSL en un espacio de nombres, como este:
#include <cstdio>
namespace OpenSSL {
#include <openssl/ssl.h>
#include <openssl/err.h>
}
Pero acabo de descubrir que esto parece hacer explotar las cosas si trato de hacerlo cuando trabajo con Boost ASIO, que tiene soporte para OpenSSL, pero parece que trae los símbolos de OpenSSL al espacio de nombres global. ¿Hay algo que pueda hacer al respecto, o simplemente tengo que dejar todos los símbolos de la biblioteca OpenSSL en el espacio de nombres global?
Simplemente pensé en probar un "uso del espacio de nombres OpenSSL" en el archivo ofensivo después de incluir mi encabezado, pero desafortunadamente causa errores como:
/usr/include/openssl/x509v3.h:83:13: error: reference to ‘v3_ext_ctx’ is ambiguous
/usr/include/openssl/x509v3.h:71:8: error: candidates are: struct v3_ext_ctx
/usr/include/openssl/ossl_typ.h:160:16: error: struct OpenSSL::v3_ext_ctx
(Tenga en cuenta que OpenSSL es una biblioteca C, no una biblioteca C ++, y por lo tanto las funciones originales no están en ningún espacio de nombres hasta que se traen a una unidad de compilación C ++. Stroustrup recomienda su técnica en su libro The C ++ Programming Language, Special Edition . De la sección 9.5, "Consejo": "[8] #incluye encabezados C en espacios de nombres para evitar nombres globales; §8.2.9.1, §9.2.2."
Entonces, el problema parece ser el siguiente: los símbolos de OpenSSL solo se pueden traer una vez; un segundo #include de ellos no tendrá ningún efecto debido a los guardias de inclusión. Eso significa que se pueden traer a un solo espacio de nombre dentro de una unidad de compilación.
Por lo tanto, si va a trabajar con Boost.ASIO en su unidad de compilación, lo que requiere que estén en el espacio de nombres global, tendrá que traerlos al espacio de nombres global usted mismo (antes de #include <boost / asio.hpp> o deje que #include <boost / asio.hpp> haga eso.
En general, esto no funcionará, y se supone que no. Boost.Asio puede (y debería) esperar poder hacer referencia a los tipos de OpenSSL como si estuvieran en el espacio de nombres global, por ejemplo, refiriéndose a ::buf_mem_st
, pero eso falla porque has hecho que se declare como OpenSSL::buf_mem_st
.
Además, ¿qué sucede si <openssl/ssl.h>
incluye otro encabezado, digamos <stddef.h>
(que lo hace) y que luego define size_t
como OpenSSL::size_t
. Cualquier código posterior que incluya <stddef.h>
no lo incluirá nuevamente porque tiene incluir macros de guardia, y ahora su programa nunca puede usar ::size_t
porque está incorrectamente declarado como OpenSSL::size_t
- para muchas implementaciones esto romperá la mayor parte de la biblioteca estándar de C ++ si se incluye después de su openssl incluye. En su caso, es posible que <cstdio>
incluya <stddef.h>
todos modos, pero lo mismo se aplica a cualquier encabezado estándar (es decir, no OpenSSL) incluido en los encabezados de OpenSSL, como <sys/types.h>
. Su programa define OpenSSL::pid_t
y OpenSSL::off_t
y OpenSSL::timeval
etc.
La única forma de solucionar ese problema es incluir cada encabezado C estándar antes de hacer su inclusión en un espacio de nombres, de modo que si OpenSSL
intenta incluir ese encabezado nuevamente, ya se haya incluido correctamente, en el espacio de nombres global. Incluso entonces, otros encabezados que se refieren a OpenSSL (como Boost.Asio) podrían romperse.
Solo di no.