Предотвращение стандартных функций вне пространства имен 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 вместо случайного, чтобы я мог сообщить людям, которые позже будут поддерживать мой код, что используемая функция НЕ является той, которая определена как стандарт.