Если я скомпилирую этот минимизированный пример с помощью clang++:
#include <system_error>
#include <vector>
namespace MyNamespace {
namespace ffi {
#include <sys/types.h>
}
void example() {
const ffi::errno_t savedErrno = errno;
ffi::uint uskip = static_cast<ffi::uint>(5);
throw std::system_error(savedErrno, std::generic_category());
}
}
Я получаю следующие ошибки:
clang++ -pedantic-errors -Weverything -Wno-c++98-compat -Wno-pre-c++20-compat-pedantic -Wno-poison-system-directories --std=c++20 -O3 -Iinclude -I/usr/local/include -MMD -MP -c -fPIC src/test.cpp -o obj/test.o
src/test.cpp:10:11: error: no type named 'errno_t' in namespace 'MyNamespace::ffi'; did you mean simply 'errno_t'?
const ffi::errno_t savedErrno = errno;
^~~~~~~~~~~~
errno_t
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/_types/_errno_t.h:30:32: note: 'errno_t' declared here
typedef int errno_t;
^
src/test.cpp:11:5: error: no type named 'uint' in namespace 'MyNamespace::ffi'; did you mean simply 'uint'?
ffi::uint uskip = static_cast<ffi::uint>(5);
^~~~~~~~~
uint
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/types.h:93:33: note: 'uint' declared here
typedef unsigned int uint; /* Sys V compatibility */
^
src/test.cpp:11:35: error: no type named 'uint' in namespace 'MyNamespace::ffi'; did you mean simply 'uint'?
ffi::uint uskip = static_cast<ffi::uint>(5);
^~~~~~~~~
uint
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/types.h:93:33: note: 'uint' declared here
typedef unsigned int uint; /* Sys V compatibility */
^
Однако если я не включу заголовок <vector>
перед пространством имен ffi
, компиляция будет работать.
По сути, почему заголовок <vector>
препятствует включению типов в пространство имен ffi
?
Заголовки библиотек обычно не пишутся таким образом, чтобы их можно было включать где угодно, кроме области глобального пространства имен. Это вызовет непосредственные проблемы, такие как сбой компиляции, но также и менее очевидные проблемы из-за нарушений ODR, которые могут привести к непреднамеренному поведению во время выполнения. Для заголовков стандартной библиотеки C++ включение их где угодно, кроме области глобального пространства имен, явно вызывает неопределенное поведение, а для POSIX можно было бы ожидать, что их включение где-либо еще также будет иметь неопределенное поведение.
<sys/types.h>
уже включен неявно через #include <system_error>
и #include <vector>
. Второй #include <sys/types.h>
в пространстве имен MyNamespace::ffi
предотвращается защитой заголовка в <sys/types.h>
.
Ты печатаешь быстрее меня. Неубедительная причина для голосования.
Я печатал комментарий, а затем решил скопировать комментарий в ответ.
Это один из редких случаев, когда я начал писать ответ, прежде чем написать комментарий.
«Второму #include <sys/types.h>
в пространстве имен MyNamespace::ffi
препятствует защита заголовка в <sys/types.h>
». - и поэтому вам следует переместить <sys/types.h>
за пределы пространства имен, а затем использовать операторы typedef
или using
внутри пространства имен, например: #include <sys/types.h> ... namespace MyNamespace { namespace ffi { using errno_t = ::errno_t; using uint = ::uint; } ... }
и т. д.
В подобных случаях часто полезно взглянуть на выходные данные препроцессора. В gcc это
-E
, и я думаю, что clang будет таким же. (подтвердила то же самое)