Почему типы выходят из пространства имен при включении после заголовка вектора?

Если я скомпилирую этот минимизированный пример с помощью 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?

В подобных случаях часто полезно взглянуть на выходные данные препроцессора. В gcc это -E, и я думаю, что clang будет таким же. (подтвердила то же самое)

user4581301 27.07.2024 00:35

Заголовки библиотек обычно не пишутся таким образом, чтобы их можно было включать где угодно, кроме области глобального пространства имен. Это вызовет непосредственные проблемы, такие как сбой компиляции, но также и менее очевидные проблемы из-за нарушений ODR, которые могут привести к непреднамеренному поведению во время выполнения. Для заголовков стандартной библиотеки C++ включение их где угодно, кроме области глобального пространства имен, явно вызывает неопределенное поведение, а для POSIX можно было бы ожидать, что их включение где-либо еще также будет иметь неопределенное поведение.

user17732522 27.07.2024 00:53
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

<sys/types.h> уже включен неявно через #include <system_error> и #include <vector>. Второй #include <sys/types.h> в пространстве имен MyNamespace::ffi предотвращается защитой заголовка в <sys/types.h>.

Ты печатаешь быстрее меня. Неубедительная причина для голосования.

user4581301 27.07.2024 00:29

Я печатал комментарий, а затем решил скопировать комментарий в ответ.

3CxEZiVlQ 27.07.2024 00:31

Это один из редких случаев, когда я начал писать ответ, прежде чем написать комментарий.

user4581301 27.07.2024 00:33

«Второму #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; } ... } и т. д.

Remy Lebeau 27.07.2024 01:44

Другие вопросы по теме

Похожие вопросы