Isnan находится в пространстве имен std::? В общем, когда std:: необходим, необязателен или его следует избегать?

В Mingw 4.7.2 у меня есть библиотека, которая не компилируется из-за вызова isnan. Компилятор говорит, что "все будет хорошо", если я использую std::isnan, и действительно мне удается скомпилировать свой файл.

Но если я проверю здесь (Изменить: но, возможно, я должен был проверить также здесь :-) ), std:: не кажется необходимым. Если я добавлю его, будет ли файл переносимым?

В общем, для каждого случая есть общий способ понять, когда установка std:: необходима (для переносимости), необязательна или ее следует избегать?

Изменить

Действительно, одной из причин проблемы является то, что есть несколько включений заголовков, и некоторые из включенных заголовков включают <cmath>, в то время как этот файл cpp пытается включить <math.h> (когда <cmath> уже включен).


person Antonio    schedule 08.08.2013    source источник
comment
Не проверяйте здесь, проверьте здесь.   -  person Christian Rau    schedule 08.08.2013
comment
@ChristianRau Так что в основном в C ++ 98 этого не существовало, и его можно было получить, только позаимствовав его из C! Это интересно!   -  person Antonio    schedule 08.08.2013
comment
Нет, так было всегда. Эта ссылка просто должна показать вам, что перед именем функции стоит большая std::. По стечению обстоятельств эта конкретная функция isnan поддерживается только в C++11 и вообще не существовала в C++98 (даже в заголовке C, который был заголовком C89/90, а не в заголовке C99, как в C++). 11 применений). Таким образом, вы могли бы позаимствовать его из C, но не из C, включенного в C++, а из настоящего C99 (хотя тогда это должно быть странное сочетание).   -  person Christian Rau    schedule 08.08.2013


Ответы (3)


Это зависит от того, какой заголовок вы включаете. Если вы включаете заголовок C <math.h> (который является частью C++, хотя и помечен как устаревший), вы можете использовать неквалифицированные функции C, такие как isnan. С другой стороны, если вы включаете заголовок C++ <cmath>, вы гарантируете только то, что он переносит все функции из <math.h> в пространство имен std, и поэтому вам нужно правильно их квалифицировать, например std::isnan (или использовать некоторые своего рода директива using). К сожалению, реализация разрешена, но не требуется для переноса этих функций в глобальное пространство имен при включении <cmath> (и, таким образом, это один из многих "работающих на моей машине» — инциденты с C++ и причина, по которой многие люди пишут код, подобный тому, который вы только что безуспешно пытались скомпилировать).

Подводя итог: либо включите <math.h> и используйте isnan, либо включите <cmath> и используйте std::isnan, все остальное непереносимо. Конечно, все это относится и к любому другому заголовку C и его соответствующей версии C++.

EDIT: Однако следует отметить, что эта конкретная функция isnan поддерживается только с C++11 и вообще не была доступна в C++98 (что может быть частью вашей путаницы). Но это ничего не меняет в данной ситуации, потому что в C++98 ни <cmath>, ни <math.h> (который тогда был фактическим заголовком C89/C90, а не заголовком C99, который включает C++11) не имели этой функции, поскольку они всегда синхронизированы. Итак, эта библиотека из вашего вопроса, возможно, пыталась использовать С++ 98, взяв функцию isnan из другой реализации C99 (что не особенно хорошая идея, поскольку она может конфликтовать с частями C89/C90 реализации С++ , никогда даже не пробовал это, хотя).

person Christian Rau    schedule 08.08.2013
comment
Так что ‹math.h› устарел! Тогда в C++98 следует использовать только ‹cmath›? И возможно ли иметь код, работающий как на C++98, так и на C++11? - person Antonio; 08.08.2013
comment
@Antonio Вся эта проблема не имеет ничего общего с C ++ 98 и C ++ 11. Это всегда было так, как описано в моем ответе, независимо от стандарта С++. И да, заголовки C называются устаревшими, но на практике это мало что значит, и это скорее вопрос вкуса, какой из них вы используете (я лично, будучи снобом против C и большим поклонником спама std:: везде, но предпочитаю заголовки C++). Но вы, конечно, должны оставаться последовательными, иначе вы испытаете такие странности, как на самом деле. - person Christian Rau; 08.08.2013
comment
[это было написано перед вашим комментарием] Глядя на комментарий/ссылку Кристиана Рау выше: иснан <cmath> не должен быть даже в С++ 98... И единственный иснан для С++ 98 будет в устаревшем <math.h>, который должен вызываться без std::. Так что быть переносимым... невозможно :), если только не поставить громоздкую условную компиляцию. - person Antonio; 08.08.2013
comment
Относительно вашего комментария: так ‹cmath› вы называете заголовком C или C++? - person Antonio; 08.08.2013
comment
@Antonio Как написано в ответе, <cmath> — это заголовок C ++, а <math.h> — это заголовок C, включенный в библиотеку C ++. - person Christian Rau; 08.08.2013
comment
@Antonio И единственный isnan для C++98 будет в устаревшем ‹math.h› - нет, <math.h> в C++98 также не имеет isnan, просто нет формы isnan вообще в С++ до 11. В этом случае портативный isnan возможен только в том случае, если вы все равно предоставите его сами. - person Christian Rau; 08.08.2013

C не имеет понятия о пространствах имен. При написании #include <math.h> все имена, объявленные в шапке, переходят в глобальное пространство имен, и нужно писать isnan.

C++ имеет пространства имен. Всё-таки при записи #include <math.h> все имена, объявленные в шапке, уходят в глобальное пространство имён, и нужно писать isnan, как и в C.

Кроме того, при написании #include <cmath> все имена, объявленные в шапке, переходят в пространство имен std, а писать нужно std::isnan.

Кроме того, реализациям C++ разрешается идти другим путем: #include <math.h> помещать имена в std а также в глобальное пространство имен, а #include <cmath> помещать имена в глобальное пространство имен а также в std. Не полагайтесь на это; код, который делает это, не является переносимым. Это уступка разработчикам, чтобы упростить задачу; на самом деле это означает, что если вы используете #include <cmath>, вы не можете предположить, что в глобальном пространстве имен не будет isnan, а если вы используете #include <math.h>, вы не можете предположить, что isnan не будет в std.

person Pete Becker    schedule 08.08.2013
comment
Итак, что произойдет, если я включу оба? (Глядя на этот конкретный пример, у меня будет непоследовательное поведение) - person Antonio; 08.08.2013
comment
@Antonio Это, вероятно, зависит от их соответствующего порядка включения и их защиты включения. Короче говоря, никогда не делайте этого. - person Christian Rau; 08.08.2013
comment
@ChristianRau Спасибо, мне просто нужен авторитетный ответ :) (я не автор библиотеки) - person Antonio; 08.08.2013
comment
@ Антонио - если вы включаете оба, вы находитесь в состоянии греха. Это не означает, что это не будет работать: стандартные заголовки должны работать правильно, независимо от того, какие другие стандартные заголовки также используются. Поэтому, если вы включите оба, вы получите имена как в std, так и в глобальном пространстве имен. - person Pete Becker; 08.08.2013

Это потому, что isnan из C. Использование другого типа include приведет к другим результатам. Возьмите isnan из заголовка C <math.h> в качестве примера:

Если вы используете #include <cmath>, оно будет помещено в пространство имен std.

Если вы используете #include <math.h>, оно будет помещено в глобальное пространство имен.

Заголовки стандартной библиотеки C++11 D.5 C

Каждый заголовок C, каждый из которых имеет имя формы name.h, ведет себя так, как если бы каждое имя, помещенное в пространство имен стандартной библиотеки с помощью соответствующего заголовка cname, помещается в глобальную область пространства имен. Не указано, были ли эти имена сначала объявлены или определены в области пространства имен (3.3.6) пространства имен std, а затем вставлены в область глобального пространства имен с помощью явных объявлений использования (7.3.3).

[Пример: заголовок обязательно предоставляет свои объявления и определения в пространстве имен std. Он также может предоставлять эти имена в глобальном пространстве имен. Заголовок, безусловно, предоставляет те же объявления и определения в глобальном пространстве имен, что и в стандарте C. Он также может предоставлять эти имена в пространстве имен std. — конец примера]

person Yu Hao    schedule 08.08.2013