none
Некорректное помещение стандартных функций С++ в глобальное пространство имен RRS feed

  • Общие обсуждения

  • В MS VC++ 2010 стандартные функции С++ из заголовочных файлов, которые являются "оберткой" для стандартных заголовочных файлов С, помимо стандартных  С-функций помещены в глобальное пространство имен также функции С++.

    Например, только стандартная С-функция double pow( double, double ) из <cmath> может быть помещена в глобальное пространство имен. Однако в MS VC++ 2010 в глобальное пространство имен помещаются и перегруженные С++-функции с именем pow.

    Хотелось бы знать, в MS VC++ 2012 RC это исправлено, или по-прежнему оставлено и считается расширением языка компилятора MS VC++?

    3 августа 2012 г. 11:42

Все ответы

  • Включает, но не по ошибке. Это часть стандарта C++. 

    http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2011/n3242.pdf

    $26.8.8 In addition to the double versions of the math functions in <cmath>, C++ adds float and long double overloaded versions of these functions, with the same semantics.

    В старом стандарте это тоже упоминалось.

    3 августа 2012 г. 12:42
    Модератор
  • Вы говорите не о том.  То, что С++ перегружает функцию pow, это известно.

    Речь же идет о другом, что С++ не должен помещать перегружаемые версии этой функции в глобальное пространство имен. То есть в глобальном пространстве имен может находиться лишь одна стандартная функция С double pow( double, double ). Все остальные функции, включая и эту стандартную функцию С, должны размещатсья в стандартном пространстве имен std::.

    То есть если отсутствует директива using namespace std; и указывается имя функции pow без вложенного префикса имен, то никакой неоднозначности не должно быть. Компилятор должен видеть только одно имя pow, то есть имя стандартной функции С.

    Вот простой демонстрационный пример

    #include "stdafx.h"
    #include <iostream>
    #include <cmath>

     

    int _tmain(int argc, _TCHAR* argv[])
    {
     {
      int x = 2, y = 3;

      std::cout << pow( x, y ) << std::endl;
     }

     return 0;
    }

    Здесь не должно быть никакой неоднозначности. И, к примеру, компилятор GCC 4.7.1 компилирует этот код без каких-либо сообщений об ошибке.

    Это следует из $4 раздела 17.6.1.2 Headers стандарта С++

    4 Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).

     

     

    3 августа 2012 г. 13:35
  • Там же в спецификации, в сноске к 17.6.1.1

    170) The C standard library headers (Annex D.5) also define names within the global namespace, while the C++ headers for C
    library facilities (17.6.1.2) may also define names within the global namespace

    MS C++ может, и помещает. GCC может, но не помещает.

    3 августа 2012 г. 13:54
    Модератор
  • На мой взгляд вы опять не о том говорите. В этой сноске имеется в виду, что помимо стандартных С макросов из этого заголовка имена функций в стандартном заголовке С также размещаются в глобальном пространстве имен. И заколовок С++ также может их поместить в глобальное пространство имен помимо пространства имен std::. Но это совершенно не оозначает, что свои собственные перегруженные версии этих функций компилятор С++ имеет право помещать в глобальное пространство имен.

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

    Поэтому GCC 4.7.1 следует стандарту, в то время как компилятор VC++ нарушает стандарт, размещая свои объявления в глобальном пространстве имен. 

     
    3 августа 2012 г. 14:07
  • В 26.8 прямо сказано, что cmath содержит перегруженные функции pow. 26.8 вообще не упоминает про пространства имен, он задает только список имен в cmath. Все перегрузки pow в этом общем списке есть.

    cmath - это один C++ headers for C library facilities. А не "заголовок C". 

    Сноска к 17.6.1.1 явно говорит, что C++ headers for C library facilities могут (но не обязаны) объявлять имена в глобальном пространстве имен. Любые имена, которые есть в этих хедерах, без каких-либо оговорок. Все перегрузки pow есть в хедере, все они могут быть добавлены в глобальное пространство имен. 

    В стандарте нет никаких оговорок про "те, что есть в C, но нет в C++". Если есть - процитируйте.


    3 августа 2012 г. 14:49
    Модератор
  • так вы сами же и процитировали, а именно  "C++ headers for C library facilities могут (но не обязаны) объявлять имена в глобальном пространстве имен". Перегруженные объявоения, которые добавляет С++ не являются C library facilities. C library facilities - это то, что описано в стандарте С. Все, точка. В стандарте С нет таких объявлений, которые дополнительно вводит С++. Открываете стандарт С и читаете про C library facilities.

    На самом деле на мой взгляд здесь достаточно прозрачно все написано (пока я не встретил ваши возражения:) ).

    Сначало в разделе 17.6.1.1 Library contents в параграфе 2 написано:

    "Э2 All library entities except macros, operator new and operator delete are defined within the namespace std or namespaces nested within namespace std.172".

    Здесь явно перечисляется какие имена объявляются в глобальном пространсвте имен, а какие в стандартном пространстве имен.

    Теперь обращаемся к сноске:

    "172) The C standard library headers (Annex D.5) also define names within the global namespace, while the C++ headers for C library facilities (17.6.1.2) may also define names within the global namespace"

    О чем здесь говорится? Здесь говорится о том, что стандартные заголовки С (именно заголовки С) также определяют имена в глобальном пространстве имен, и что С++ эти объявления С (заметьте: объявления С, а не С++) также может поместить в глобальное пространство имен.

    Далее в параграфе 4 написано:

    "4 Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3)."

    Что в заголовках С++ объявления, которые совпадают с объявлениями из С (чтобы вы не спрашивали, откуда я это взял, то цитирую: "the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library"), то есть в данном параграфе речь идет об объявлениях, которые описаны (подчеркиваю, описаны) в стандарте С  (as specified in the C standard library), размещены в пространстве имен std::, но при этом на усмотрение разработчиков компилятора разрешается помещать их в глобальное пространство имен.

    Перегруженные объявления, которые добавляет С++, не описаны в стандарте С, а потому не моогут быть помещены в глобальное пространстов имен. В глобальное пространстов имен могут быть помещены объявления только те, которые имеются в стандартном заголовке С "as specified in the C standard library"

    3 августа 2012 г. 15:18
  • >> C library facilities - это то, что описано в стандарте С. 

    C++ headers for C library facilities - это то, что описано в стандарте C++, в 17.6.1.2 - 26 заголовков с именами вида cname. Содержимое этих заголовков тоже описано стандартом C++ (а не стандартом C). Если стандарт говорит, что в заголовке cmath есть несколько функций pow - то значит они там просто есть, без разделения на "они там есть потому что были в C" и "в C++ мы смогли их добавить". Все упоминания C++ headers for C library facilities - это, дословно "хедеры с именами cname, перечисленные в таблице 15". 

    Для "the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library" есть специальная оговорка, именно для cmath: 

    "The contents of these headers are the same as the Standard C library headers <math.h> and <stdlib.h>
    respectively, with the following changes:....". 

    --------------------

    >>>"172) The C standard library headers (Annex D.5) also define names within the global namespace, while the C++ headers for C library facilities (17.6.1.2) may also define names within the global namespace"

    >>>О чем здесь говорится? Здесь говорится о том, что стандартные заголовки С (именно заголовки С) также определяют имена в глобальном пространстве имен, и что С++ эти объявления С (заметьте: объявления С, а не С++) также может поместить в глобальное пространство имен.

    Вы немного некорректно перевели. Там не сказано "С++ эти объявления С (объявления С, а не С++)". Там написано просто names. Дословно: "в тоже время, <заголовки C++, перечисленные в 17.6.1.2, таблице 15> могут объявлять имена в глобальном пространстве имен. Никаких same names, that names, names that inherited from C headers там нет.

    Заголовки C++ (не C), и имена из C++ (не только из C).

    --------------------

    >> Перегруженные объявления, которые добавляет С++, не описаны в стандарте С, а потому не моогут быть помещены в глобальное пространстов имен. 

    Если точно по стандарту - то все новые методы стандарт прямо добавляет в cmath (в хедер), а не просто "вникуда". Хедер является одним из "C++ headers for C library facilities" - потому что он есть в списке. Имена из любого хедера из списка "C++ headers for C library facilities" могут быть помещены в глобальное пространство имен. На мой взгляд, тут все вполне однозначно, и не надо ничего читать между строк. 

    Если у вас есть стойкое ощущение что это баг - отпишитесь в connect, только ошибку приведите из 12-й студии, иначе закроют как "2010 не поддерживаем".

    3 августа 2012 г. 16:32
    Модератор
  • На мой взгляд здесь говорится о том, что стандартные заголовки С++ должны в точности соответствовать заголовкам С за некоторыми исключениячми, которые упоминаются.

    Что касается имен, то я считаю, что речь идет об объявлениях, присутствующих в стандартных заголовках С в соответствии с описанием их в стандарте С. Именно эти объявления могут быть помещены в глобальное пространство имен. То есть на мой взгляд речь идет о совместимости. Если использовать заголовок С++ в коде, написанном на С, и не применять ни директивву using namespace std, ни указывать специально вложенное имя std::, то код должен компилироваться, как будто бы он компилируется С компилятором. То есть не должна нарушаться совместимость кода.

    Так как вопрос оказался достаточно спорным и позволяет две противоположные трактовки, то я решил подключить к этому вопросу других специалистов по С++, задав этот вопрос в google на форуме по обсуждению вопросов текущего стандарта. Будет интересно узнать их точку зрения. Тогда я здесь о ней сообщу.

    3 августа 2012 г. 17:00
  • Дело в том, что если принять вашу точку зрения, то тогда выходит, что GCC 4.7.1 содержит баг, так как он не может выборочно помещать лишь отдельные объявления одного имени из заголовка в глобальное пространство имен. Либо он должен был бы все стнадартные имена С из заголовка <cmath> включить в глобальное пространстов имен, либо ни одного именип не включать. Или по крайней мере должен ббыл бы все объявления имени pow включить в глобальное пространство имен.

    Ежели следовать вашей логике, то получается, что разработчик компилятора может в глобальное пространство имен включить только, например, функцию

    long double pow( long double, long double)

    которой нет в стандарте С, а функцию

    double pow( double, double)

    , которая описана в стандарте С, не включать в глобальное пространство имен. Какой вы видите в этом смысл?!

    3 августа 2012 г. 17:07
  • Насчет выборочных объявлений никаких упоминаний (и запретов) в стандарте вроде нет, так что это скорее не баг в GCC или MS VS, а просто разные реализации. Хотите совместимости - всегда приписывайте std::

    Смысла добавлять только не-С-вариант никакого нет, поэтому так никто и не делает :)

    3 августа 2012 г. 17:34
    Модератор
  • Правильно, а тогда зачем стандарту это разрешать делать?! Я думаю, что в стандарте имели в виду другое, а именно совместимость с С кодом, то есть возможность компилировать С-код компилятором С++.
    3 августа 2012 г. 17:39
  • Я еще раз внимательно тпрочитал параграф 4 раздела 17.6.1.2 Headers стандарта,

    "4 Except as noted in Clauses 18 through 30 and Annex D, the contents of each header cname shall be the same as that of the corresponding header name.h, as specified in the C standard library (1.2) or the C Unicode TR, as appropriate, as if by inclusion. In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std. It is unspecified whether these names are first declared within the global namespace scope and are then injected into namespace std by explicit using-declarations (7.3.3).", и еще раз пришел к выводу, что я прав, так как ваша трактовка вообще лишена какого-то смысла в том плане, что совершенно не ясно, какие цели может преследовать ваша трактовка.

    В этом прагарфе говорится о стандартных  объявлениях языка С, и как они переносят в язык С++. Эти слова "as specified in the C standard library (1.2) or the C Unicode TR" однозначно говорят об этом. Далее ы следующей фразе "In the C++ standard library, however, the declarations (except for names which are defined as macros in C) are within namespace scope (3.3.6) of the namespace std." говорится об объявлениях С, которые переносятся в С++, и эти объявления, то есть объявления С, в С++ помещаются в стандартное пространство имен. И затем написано, что не указано, могут ли эти имена (имеется в виду эти объявления) помещаться в глобальное пространство имен.

    То тесть этот параграф посвящен только стандартным объявлениям С, и говорится, как с ними может поступить разработчик компилятора С++. Ни о каких других объявлениях, которые могут быть добавлены разработчиком компилятора С++ в соответсвии со стандартом С++, здесь речи не идет. Так как добавляемые объявления не являются стандартными объявлениями С.  А речь идет именно о стандартных объявлениях С.

    В этом и заключается смысл этого параграфа, что разработчики компиляторов С++ могут обеспечить совместимость с С, если включат стандартные объявления С в глобальное пространство имен. То, что делает VC++, включая дополнительные объявления в глобальное пространство имен, просто лишено всякого смысла, так как эти объявления не входят в число стандартных объявлений С.

     

    3 августа 2012 г. 18:12
  • Привет, как уже сказал PashaPash выше, попробуйте написать баг-репорт на Microsoft Connect по Visual Studio 2012.

    Нативная разработка в Visual Studio больше ориентирована на C++, а не на C, посмотрите к примеру это обсуждение - How can I use Visual Studio 2010 for C development?

    Если для вас эта проблема настолько критична и вы собираесь писать C приложения, то может лучше использовать не Visual C компилятор? C/C++ в Visual Studio давно и особых проблем у разработчиков не возникало с этой возможно особенностью определения перегруженных функций.


    Для связи [mail]

    16 августа 2012 г. 11:02