Использование полного имени для пространства имен std в C++

Если имя в С++ не является полным, например. std::cout, это может привести к непреднамеренной ошибке, как указано на https://en.cppreference.com/w/cpp/language/qualified_lookup. Но используя полное имя для пространства имен ::std, например. ::std::cout, как я заметил, встречается очень редко.

Есть ли причина, по которой полное имя для пространства имен ::std не используется?

А как насчет использования полного имени для собственных созданных пространств имен? Это хорошая идея?


person Kam    schedule 17.02.2019    source источник
comment
Это потому, что любой, кто создает вложенный класс или пространство имен с именем std, должен быть выдворен из кампуса в тот момент, когда он делает коммит. Так что это не проблема на практике.   -  person n. 1.8e9-where's-my-share m.    schedule 17.02.2019
comment
@н.м. Превосходно ! Соответственно, я обновил формулировку своего ответа с «Никто не будет называть класс стандартным» на «Никто не посмеет назвать класс стандартным» ;-)   -  person Christophe    schedule 17.02.2019
comment
@н.м. Разве это не стоит более подробной разработки, чтобы развить ответ? Почему только короткий комментарий?   -  person Red.Wave    schedule 17.02.2019
comment
@Red.Wave Это просто шутка.   -  person n. 1.8e9-where's-my-share m.    schedule 17.02.2019
comment
@н.м. Это больше. Потому что у него есть точка, и она фактически попадает в центральную точку.   -  person Red.Wave    schedule 17.02.2019


Ответы (2)


Вы совершенно правы в том смысле, что yyyy::xxx может быть неоднозначным, если есть пространство имен yyyy, а также класс yyyy, которые видны в одной и той же области. В этом случае только полная квалификация ::yyyy::xxx может разрешить неоднозначность. Пример вашей ссылки делает это очень ясным:

// from cppreference.com
#include <iostream>
int main() {
  struct std{};
  std::cout << "fail\n"; // Error: unqualified lookup for 'std' finds the struct
  ::std::cout << "ok\n"; // OK: ::std finds the namespace std
}

Но на практике сложно создать конфликтующий std на верхнем уровне, так как большинство включений из стандартной библиотеки приведут к сбою:

#include <iostream>

struct std {      // OUCH: error: ‘struct std’ redeclared as different kind of symbol
    int hello;  
}; 

Это означает, что для создания конфликта вам нужно определить локальные классы или ввести предложение using в другом пространстве имен. Кроме того, никто не посмеет назвать класс std.

Наконец, на практике ::yyyy::xxx менее удобно читать. Все это объясняет, почему вы не найдете его очень часто.

Дополнительное замечание

Проблема не столько в хорошо известном std, сколько в ваших собственных пространствах имен и сторонних библиотеках. В этом случае псевдоним пространства имен будет лучшей альтернативой :::yyyy для устранения неоднозначности:

namespace foo {
    void printf() { }
}
int main() {
    foo::printf();          // ok, namespace is chose because no ambiguity
    struct foo {/*...*/ };  // creates ambiguity
    //foo::printf();        // error because struct foo is chosen by name lookup
    ::foo::printf();        // ok, but not if you  decide to move the code to be nested in another namespace
    namespace  mylib = foo ;   // or ::foo (see discussion below)
    mylib::printf();        // full flexibility :-)
}

Его преимуществом является более высокая гибкость. Предположим, например, что вы переместите свой код, чтобы вложить его во вмещающее пространство имен. С псевдонимом пространства имен ваш код может продолжать работать как есть (в худшем случае с незначительной корректировкой определения псевдонима). При разрешении глобальной области видимости вам придется изменить все операторы, в которых будет использоваться глобальное пространство имен ::foo.

person Christophe    schedule 17.02.2019
comment
namspace mycrazyspace{ namespace std{ /* мой психопат*/};}; Никто не осмеливается сделать это. Но я могу быть достаточно сумасшедшим, чтобы пойти на это!!!!???? И тулчейн не заметит никаких ошибок. - person Red.Wave; 17.02.2019
comment
@Red.Wave :-D Ты сделал мой день! Конечно, вы можете это сделать! И вы даже сможете использовать оператор разрешения глобальной области видимости, когда это необходимо для устранения неоднозначности: по крайней мере, у нас будет кто-то, кому понравится эта языковая функция ;-) Шутки в сторону, эта функция также может иметь смысл для других пространств имен, кроме std, где конфликты случаются чаще. И я предполагаю, что он в основном будет использоваться для создания менее двусмысленных псевдонимов. - person Christophe; 17.02.2019
comment
Я не хочу беспокоить, но я хочу сказать, что предоставленный ответ нуждается в пересмотре. - person Red.Wave; 17.02.2019

Чтобы сохранить большой код или лучшую читаемость или конфликты в именах, C++ предоставил пространство имен «декларативную область». Определение пространства имен может отображаться только в глобальной области видимости или быть вложенным в другое пространство имен.

#Sample Code
#include <iostream>
int main() 
{
      struct std{};
      std::cout << "fail\n"; // Error: unqualified lookup for 'std' finds the struct
      ::std::cout << "ok\n"; // OK: ::std finds the namespace std
}

В приведенном выше коде компилятор ищет cout в struct std , но в следующей строке, когда вы используете ::std::cout, он ищет cout в глобально определенном стандартном классе.

Решение:

#include <iostream>
//using namespace std; // using keyword allows you to import an entire namespace at once. 

namespace test
{
    void cout(std::string str)
    {
       ::std::cout<<str; 
    }
}

int main() 
{
    cout("Hello");//'cout' was not declared in this scope
    ::test::cout("Helloo ") ;
    ::std::cout<<"it is also ok\n";
}

Или используйте таким образом, это просто для лучшей читабельности

##
using namespace test;
int main() 
{
    cout("Hello");//'cout' was not declared in this scope
    cout("Helloo ") ;
    ::std::cout<<"it is also ok\n";
}
person Gaurav G    schedule 17.02.2019
comment
Интересно! Вы также можете определить псевдоним пространства имен, namespace mystd = ::std;. В этом случае вы можете просто обратиться к mystd::cout. Если позже вы предпочтете использовать собственную альтернативную библиотеку, вы можете изменить псевдоним на namespace mystd = test;, не изменяя остальную часть кода, использующего mystd. - person Christophe; 17.02.2019