Почему std:: не требуется при использовании ispunct() в С++?

#include <iostream>
#include <string>
#include <cctype>

using std::string;
using std::cin;
using std::cout; using std::endl;

int main()
{
    string s("Hello World!!!");
    decltype(s.size()) punct_cnt = 0;
    for (auto c : s)
        if (ispunct(c))
            ++punct_cnt;
    cout << punct_cnt
         << " punctuation characters in " << s << endl;
}

Кажется, я могу использовать ispunct() без std:: или объявлять using std::ispunct;, но я не могу сделать это с помощью std::cout или std::cin. Почему это происходит?

Ответ 1

Это означает, что ispunct является частью глобального пространства имен, а не пространства имен std. Вероятно, это потому, что ispunct является одной из функций, возвращаемых из C (следовательно, она находится в cctype).

С другой стороны, cout и cin являются частью пространства имен std, а не глобального пространства имен.

Изменить:

Что касается того, почему вещи из C находятся в глобальном пространстве имен, а не в пространстве имен std, я полагаю, что это связано с тем, что C-код компилируется компилятором С++ с минимальными изменениями, поскольку С++ стремится к совместимости с C.

В соответствии с комментариями ispunct разрешено, но не требуется, чтобы находиться в глобальном пространстве имен (но требуется). в пространстве имен std), в <cctype>. Однако, если бы вы включили <ctype.h>, ispunct был бы обязательным, чтобы находиться в глобальном пространстве имен.

Ответ 2

С именами (те, которые вы получаете от включения заголовка xxx.h из C) разрешено находиться в глобальном пространстве имен в дополнение к пространству имен ::std, даже если вы включаете версию заголовка cxxx. Это было сделано, потому что проблема не в том, чтобы иметь в глобальном пространстве имен, если вы предоставляете реализацию на С++, но не в реализации C (поэтому фактические заголовки C принадлежат компилятору, который вы не контролируете).

В вашем случае ispunct поступает из заголовка ctype.h. Хотя вы включаете заголовок cctype, это, в свою очередь, включает заголовок ctype.h, который объявляет символ ispunct в глобальном пространстве имен.

Ответ 3

Заголовки С++, полученные из C (например, <cctype>), должны помещать имена тех вещей, которые они объявляют в пространстве имен std, и они разрешены также помещают их в глобальный Пространство имен. Формально это не разрешалось до С++ 11, но старое правило, согласно которому эти заголовки не могли помещать имена в глобальное пространство имен, не могло быть реализовано разумно и обычно игнорировалось.