Заголовки устаревшей стандартной библиотеки C и перегруженные функции C ++

Стандарт языка C ++ говорит в D.5

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

3 [Пример: заголовок <cstdlib> несомненно предоставляет свои объявления и определения в пространстве имен std. Он также может предоставлять эти имена в глобальном пространстве имен. Заголовок <stdlib.h>, несомненно, предоставляет те же объявления и определения в глобальном пространстве имен, как и в стандарте C. Он также может предоставлять эти имена в пространстве имен std. —Конечный пример]

Кажется, здесь довольно явно указано («... каждое имя ...», «... те же объявления ...»), что заголовки <name.h> старого стиля должны предоставлять тот же набор объявлений, что и <cname> нового стиля заголовки, но в глобальном пространстве имен. Например, не делается никаких исключений для специфичных для C ++ перегруженных версий различных функций C.

Это означает, что <math.h> должен предоставлять три версии функции sin: sin(float), sin(double) и sin(long double) в глобальном пространстве имен. Это, в свою очередь, означает, что следующий код C ++ не сможет разрешить перегрузку.

#include <math.h>

int main() {
  sin(1);
}

Он не работает под компилятором MSVC ++, но успешно компилируется под GCC и Clang. Итак, игнорирует ли GCC стандартное требование в отношении устаревших заголовков в старом стиле? Или я как-то неправильно интерпретирую формулировку в стандарте?


person AnT    schedule 06.11.2014    source источник
comment
Раздел 17.6.2.3.1 позволяет реализации давать extern "C" связь с именами из стандартной библиотеки C, объявленной с внешней связью (хотя он рекомендует этого не делать). Если бы реализация сделала это, она не смогла бы определить три разные версии sin().   -  person Crowman    schedule 07.11.2014
comment
Я думаю, вы хотели сказать, что ‹cmath› должен предоставить три версии. . . поскольку math.h - это файл заголовка C. Итак, имея это в виду, проблем с перегрузкой не возникнет, поскольку существует только одна версия sin, но три версии std :: sin.   -  person iheanyi    schedule 07.11.2014
comment
@iheanyi: файлы заголовков можно легко компилировать между C и C ++. Если ничего не помогает, #ifdef __cplusplus всегда может спасти положение.   -  person AnT    schedule 07.11.2014
comment
Да и нет. Вы не можете включить ‹math.h›, а затем использовать std :: sin, потому что его нет в math.h. #ifdef __cplusplus или нет.   -  person iheanyi    schedule 07.11.2014
comment
@iheanyi: Э ... При чем здесь конкретно std::sin? Во-первых, вопрос касается sin в math.h, а не std::sin. Во-вторых, хотя это и не тема, стандарт C ++ фактически заявляет, что math.h разрешено дополнительно предоставлять эти имена в пространстве имен std (см. Стандартную цитату выше)   -  person AnT    schedule 07.11.2014
comment
@iheanyi: Похоже, вы заблуждаетесь, полагая, что реализации C ++ каким-то образом должны использовать оригинальные чистые реализации C заголовков <name.h>. На самом деле это даже отдаленно не так.   -  person AnT    schedule 07.11.2014
comment
Нет, у меня нет такой веры. Но кто-то делает общее заявление о том, что они могут использовать заголовки c и c ++ как взаимозаменяемые, просто ifdeffing _cplusplus явно не понимает, о чем они говорят. То, что что-то разрешено, не означает, что это произойдет. Я отвечал на ваш комментарий. Заголовочные файлы могут легко компилироваться между C и C ++. Если бы это было оффтопом, возможно, вам не стоило писать комментарий. Ваше собственное недопонимание в вопросе, который вы разместили, указывает на то, что вы немного не уверены в этом вопросе.   -  person iheanyi    schedule 07.11.2014


Ответы (1)


Благодаря комментариям @hvd я увидел свет, оказалось, что MSVC верен, и GCC также должен жаловаться на двусмысленность.

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

person user657267    schedule 06.11.2014
comment
Да, но как это согласуется с тем, что говорит D.5? По сути, он говорит, что math.h должен предоставлять те же объявления, что и cmath. - person AnT; 07.11.2014
comment
@AndreyT [заголовки] 4 За исключением случаев, указанных в пунктах 18–30 и Приложении D, содержимое каждого заголовка cname должно быть таким же, как и соответствующее имя заголовка. H, [...] . Я полагаю, что формулировка в D.5 неоднозначна. - person user657267; 07.11.2014
comment
@AndreyT Если подумать, это не двусмысленно: In addition to the double versions of the math functions in <cmath> технически перегрузки вообще не являются частью <cmath>. Я предполагаю, что они волшебным образом включены феей препроцессора. - person user657267; 07.11.2014
comment
Это совсем не двусмысленно и не говорит то, что вы говорите, оно делает. C указывает double sin(double); в <math.h>. C ++ указывает, что <cmath> похож на <math.h> в C, плюс он добавляет float sin(float); и long double sin(long double); в дополнение к версии double. Затем C ++ указывает, что <math.h> похоже на <cmath> в C ++, за исключением того, что имена объявлены в глобальном пространстве имен. Нигде нет никаких указаний на то, что <math.h> C ++ совпадает с <math.h> C. Для этих переопределений требуется <math.h> C ++, если в противном случае вы не можете найти явный оператор в стандарте. - person ; 07.11.2014
comment
@hvd Как указывает мой второй комментарий, не похоже, что перегрузки изначально являются частью <cmath>. Конечно, формулировка была бы примерно такой: «В дополнение к двойным версиям математических функций в заголовке стандартной библиотеки C» ‹math.h›? - person user657267; 07.11.2014
comment
@ user657267 Они будут означать то же самое, поскольку в предыдущем тексте уже говорилось, что <cmath> C ++ объявляет то же double sin(double);, что и <math.h> C. - person ; 07.11.2014
comment
@ user657267 В результате C ++ объявляет float sin(float);, double sin(double); и long double sin(long double); в <cmath>, и, исходя из этого результата, легче понять, как вы можете этого добиться: помимо версий double ... в <cmath> относится к double sin(double); и float sin(float); и long double sin(long double); добавляются к этому. - person ; 07.11.2014
comment
@hvd Мне потребовалось время, но я думаю, что наконец понял. Я понял, что приложение D в значительной степени подразумевает, что заголовки .h должны быть практически идентичны заголовкам стандартной библиотеки C. Конечно, сейчас я не могу удалить свой ответ ... - person user657267; 07.11.2014
comment
@ user657267 Но вы можете отредактировать свой ответ. Радикальное изменение текста существующего ответа обычно не приветствуется, но в этом случае, как вы говорите, у вас нет возможности удалить свой старый, поэтому я думаю, что это будет лучший вариант для . - person ; 07.11.2014