Предотвращение стандартных функций вне пространства имен std
Я использую только файлы заголовков, специфичные для С++ (например, <cstdlib>
), однако я все еще получаю глобально объявленные функции, а не только функции в пространстве имен std
. Есть ли способ, возможно, компилятор, чтобы предотвратить это?
Например, следующий код:
#include <cstdlib>
float random() { return 0.0f; }
int main() { return 0; }
Не удалось скомпилировать под Linux, со следующей ошибкой:
> g++ -c main.cpp main.o
main.cpp: In function ‘float random()’:
main.cpp:2:14: error: new declaration ‘float random()’
/usr/include/stdlib.h:327:17: error: ambiguates old declaration ‘long int random()’
или
> clang++ main.cpp -o main.o
main.cpp:2:7: error: functions that differ only in their return type cannot be overloaded
float random() { return 0.0f; }
/usr/include/stdlib.h:327:17: note: previous declaration is here
extern long int random (void) __THROW;
который вызван тем, что stdlib.h
"загрязняет" глобальное пространство имен своей собственной функцией random
.
Обратите внимание, что я не сталкиваюсь с этими проблемами при компиляции в Windows, используя Visual Studio.
Ответы
Ответ 1
-
<cstdlib>
всегда будет заполнять пространство имен std, а иногда и определять глобальные символы, а <stdlib.h>
всегда будет определять глобальные символы и иногда заполнять пространство имен std. Это зависит от реализации и реализации.
-
Стандарт пишет:
Каждый заголовок C, каждый из которых имеет имя формы name.h
, ведет себя так, как будто каждое имя, помещенное в пространство имен стандартной библиотеки соответствующим заголовком cname
, помещается в область глобального пространства имен. Неизвестно, будут ли эти имена впервые объявлены или определены в пространстве пространства имен (3.3.6) пространства имен std
и затем будут введены в область глобального пространства имен явным использованием-деклараций (7.3.3).
Это означает, что компилятор разрешен помещать эти символы в глобальную область и std
namespace одновременно.
-
Следовательно, мы не видим преимуществ, чтобы предпочесть один заголовочный файл над другим. Поскольку , они оба очень сильно загрязняют глобальную область.
Однако при использовании #include <cstdlib>
по-прежнему необходимо использовать пространство имен std
и не использовать std
, когда #include <stdlib.h>
, чтобы ваш код мог компилироваться для всех реализаций компилятора.
-
Совет: Не используйте имена в стандартных библиотеках. Во-первых, они не гарантированно работают. (Примечание. Немногие реализации компилятора фактически сохраняют глобальную область чистой, когда вы #include <csomething>
, поэтому никогда не зависите от этого.) Во-вторых, это путает читателей кода и сопровождающих, потому что почти все будут считать, что стандартные имена фактически являются стандартными, независимо от того, где они из.
Ответ 2
Вы можете объявить свои функции в своих собственных пространствах имен, чтобы предотвратить столкновение объявлений.
namespace MyFunc
{
float random() { return 0.0f; }
};
Ответ 3
В целом вы должны стараться избегать повторного использования в первую очередь.
Это можно сделать либо с помощью пространств имен, либо путем разделения источника на файлы, которые могут включать cstdlib
и другие, которые могут использовать static
версию вашей (именной) функции.
Если это не параметры, продолжайте чтение. Но имейте в виду, что следующее может быть очень специфичным для платформы.
Просто взглянув на мои cstdlib
и stdlib.h
здесь, на моем месте, я заметил, что есть переключатель, по которому cstdlib
решает, включает ли он stdlib.h
или просто объявляет abort
, atext
и exit
в пространстве имен std
.
Очевидно, вы втягиваете ветвь stdlib.h
. Глядя дальше в этот файл, я заметил макрос __BEGIN_NAMESPACE_STD
и позже __END_NAMESPACE_STD
. Возможно, вы могли бы использовать это, но это (как подсказывает название) некоторые внутренние макросы реализации и не должны устанавливаться непосредственно вами. Однако, по какой-то причине он должен быть там, поэтому вам может быть повезло с его поиском.
После еще нескольких поисков оказалось, что random
является одной из нескольких функций (и деклараций), которые не завернуты в __BEGIN_NAMESPACE_STD
. Поэтому это не решение проблемы. (Я нашел еще один макрос _GLIBCPP_USE_NAMESPACES
, который, как представляется, используется также внутри #define __BEGIN_NAMESPACE_STD namespace std {
).
Итак, чтобы подвести итог: это не жизнеспособный путь, и вы должны использовать одно из описанных обходных решений.
Ответ 4
Стандарт явно позволяет заголовкам <c???>
вводить имена стандартных функций C в глобальное пространство имен.
Ответ 5
обычно я предпочитаю, чтобы ваши имена функций отличались от того, что определено как стандарт.
Для ex здесь можно использовать имя функции как myRandom вместо случайного, чтобы я мог сообщить людям, которые позже будут поддерживать мой код, что используемая функция НЕ является той, которая определена как стандарт.