Почему <cmath>предоставляет сущности вне пространства имен std? - PullRequest
2 голосов
/ 20 марта 2020

Насколько я понимаю, C -используемые C ++ объекты, такие как <math.h>, могут быть безопасно включены в пространство имен std, включая соответствующий вариант <c...> (за исключением макросов, очевидно) , cppreference, кажется, подтверждает это .

Однако, включая <cmath>, кажется, что функция log выходит за пределы пространство имен std:

#include <cmath>

namespace log {}

int main() {}

Скомпилировано с g++ -Wall -Wextra -pedantic -std=c++17 a.cpp выход:

a.cpp:3:11: error: ‘namespace log { }’ redeclared as different kind of entity
    3 | namespace log {}
      |           ^~~
In file included from /usr/include/features.h:446,
                 from /usr/include/x86_64-linux-gnu/c++/9/bits/os_defines.h:39,
                 from /usr/include/x86_64-linux-gnu/c++/9/bits/c++config.h:524,
                 from /usr/include/c++/9/cmath:41,
                 from a.cpp:1:
/usr/include/x86_64-linux-gnu/bits/mathcalls.h:104:1: note: previous declaration ‘double log(double)’
  104 | __MATHCALL_VEC (log,, (_Mdouble_ __x));
      | ^~~~~~~~~~~~~~

Моя стандартная библиотека не работает? Могу ли я что-то сделать, чтобы избежать этого?


Я изначально наткнулся на это, используя <random>, что означает, что на другие заголовки могут влиять явно случайные C объекты, извергаемые по всему пространство имен верхнего уровня.

Ответы [ 2 ]

2 голосов
/ 20 марта 2020

Почему <cmath> предоставляет объекты вне пространства имен std?

Из-за истории.

<cmath> заголовок является заголовком, унаследованным от C стандартная библиотека (где она называется <math.h>). В языке C существует только глобальное пространство имен 1 , в котором объявлены все имена.

Поскольку многие реализации C ++ также являются реализациями C, они часто реализуют унаследованные * 1050. * стандартный заголовок, включающий его как есть 2 , что означает, что он объявляет глобальные имена.

Хотя могут существовать методы, позволяющие избежать (за исключением стандартных макросов) объявления глобальных имен, он маловероятно, что реализации, которые делали это до стандартизации, изменили бы поведение, потому что это нарушило бы обратную совместимость.

Не работает ли моя стандартная библиотека?

Нет. Стандарт C ++ позволяет это; Все стандартные имена библиотек C зарезервированы для этого (или любого) использования языковой реализацией. Вы не можете определять их самостоятельно.

Могу ли я что-то сделать, чтобы избежать этого?

Вы обычно не можете запретить стандартной библиотеке делать это.

Вы технически можно избежать большей части этого, выбрав использование автономной языковой реализации. Но если вы выберете это, вы потеряете почти всю стандартную библиотеку.

Вы можете минимизировать вероятность конфликта имен, избегая объявления любых глобальных имен самостоятельно, за исключением одного пространства имен с достаточно уникальным именем. Что-то вроде:

namespace usr_bitmask::log {

}

1 Обратите внимание, что понятие "пространство имен" в языке C является чем-то другим.

2 И, кроме того, повторно объявляет имена в пространстве имен std при использовании именованного заголовка <c..., а также добавляет специфические для C ++ перегрузки c в некоторых случаях.

0 голосов
/ 20 марта 2020

Может быть, кто-то с большим знанием C / C ++ Standard докажет, что я не прав, но для того, чтобы компилятор C ++ мог обрабатывать C -Code, функции из C -Library должны находиться вне пространств имен, в Фактически вы должны просто найти определения C -Library, заключенные во внешнюю "C", чтобы вы могли прозрачно использовать старые функции C внутри вашего кода C ++

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...