using namespace XXX vs namespace XXX {
От: johny5 Новая Зеландия
Дата: 19.08.13 00:03
Оценка:
Всем привет.

Встретил в коде обескураживающее место.
Обычно мы пишем вот так:

//header
namespace N
{
   class C
   {
      void func();
   }
}

//cpp file
namespace N
{
   void C::func()
   {
      ..
   }
}


Однако увидел пример такого:
// header такой же

//cpp file
using namespace N;

void C::func()
{
   ..
}


И что прекрасно компилируется и работает.

Попинайте, разве как во втором случае — предпочтительнее писать? Есть ли какая разница между двумя конструкциями.
Re: using namespace XXX vs namespace XXX {
От: ArtDenis Россия  
Дата: 19.08.13 02:37
Оценка: -1
Здравствуйте, johny5, Вы писали:

J>Встретил в коде обескураживающее место.

Ну так почитай наконец-то какую-нибудь книжку по с++ и такие места не будут обескураживать

J>Однако увидел пример такого:

J>
J>// header такой же

J>//cpp file
J>using namespace N;

J>void C::func()
J>{
J>   ..
J>}
J>


Ты не поверишь, но ещё можно и так:
//cpp file
void N::C::func()
{
   ..
}


J>Попинайте, разве как во втором случае — предпочтительнее писать?

Как тебе в данный момент удобно, так и предпочтительнее
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re: using namespace XXX vs namespace XXX {
От: Chorkov Россия  
Дата: 19.08.13 07:30
Оценка:
Здравствуйте, johny5, Вы писали:

J>Всем привет.

...
J>Попинайте, разве как во втором случае — предпочтительнее писать? Есть ли какая разница между двумя конструкциями.

Если в глобальном пространстве имен появится еще один класс С, то вариант "namespace N {" сразу станет более удобным.
Одноименные классы могут сыскаться и в std::, и в boost:: ... , а "using namespace std" почти общеупотребительная практика для .cpp .
Более того, одноименные классы могут внезапно появиться, с обновлением boost, или компилятора...
Re[2]: using namespace XXX vs namespace XXX {
От: johny5 Новая Зеландия
Дата: 19.08.13 10:43
Оценка:
Здравствуйте, Chorkov, Вы писали:

C>Здравствуйте, johny5, Вы писали:


J>>Всем привет.

C>...
J>>Попинайте, разве как во втором случае — предпочтительнее писать? Есть ли какая разница между двумя конструкциями.

C>Если в глобальном пространстве имен появится еще один класс С, то вариант "namespace N {" сразу станет более удобным.

C>Одноименные классы могут сыскаться и в std::, и в boost:: ... , а "using namespace std" почти общеупотребительная практика для .cpp .
C>Более того, одноименные классы могут внезапно появиться, с обновлением boost, или компилятора...

Понятно.
Не знал что при definition-е функции компилятор также занимается поиском в пространствах имён к какому именно это определение относится. Что компилер ищет про неймспейсам при использовании чего то (класса, функции) — это общеизвестно, но вот этот случай я вижу вообще впервые. Имхо это ненужная диковинка для гиков
Re[2]: using namespace XXX vs namespace XXX {
От: B0FEE664  
Дата: 20.08.13 15:30
Оценка:
Здравствуйте, Chorkov, Вы писали:

C> "using namespace std" почти общеупотребительная практика для .cpp .


Такая практика может легко привести к переписыванию кода при переходе на новый стандарт:

#include <iostream>

using namespace std;
int error_code = 1;

int main(int argc, char * argv[])
{
  //...

  cout << error_code << endl;// surprise (probably)
  return 0;
}
И каждый день — без права на ошибку...
Re[3]: using namespace XXX vs namespace XXX {
От: johny5 Новая Зеландия
Дата: 12.09.13 12:29
Оценка:
Здравствуйте, johny5, Вы писали:
J>Здравствуйте, Chorkov, Вы писали:

J>Понятно.

J>Не знал что при definition-е функции компилятор также занимается поиском в пространствах имён к какому именно это определение относится. Что компилер ищет про неймспейсам при использовании чего то (класса, функции) — это общеизвестно, но вот этот случай я вижу вообще впервые. Имхо это ненужная диковинка для гиков

Кстате, не заработало для перегрузки operator++ для enum:

namespace N
{

  enum Blabla
  {
  };

  // prefix (++my_member)
  Blabla& operator++(Blabla& orig);

  // postfix (my_member++)
  Blabla operator++(Blabla& orig, int);
}

using namespace N;


// prefix (++my_member)
Blabla& operator++(Blabla& orig)
{
  return orig;
}

// postfix (my_member++)
Blabla operator++(Blabla& orig, int)
{
  return ++orig;
  // error C2593: 'operator ++' is ambiguous
  // could be 'N::Blabla &operator ++(N::Blabla &)'
  // or       'N::Blabla &N::operator ++(N::Blabla &)'
  // while trying to match the argument list '(N::Blabla)'
}


Если поместить операторы в namespace N — работает.
Возможно баг компайлера, VS2010.
Re[4]: using namespace XXX vs namespace XXX {
От: Zhendos  
Дата: 12.09.13 12:37
Оценка:
Здравствуйте, johny5, Вы писали:

J>Если поместить операторы в namespace N — работает.

J>Возможно баг компайлера, VS2010.

gcc тоже считает этот код ошибочным, как и clang,
но ругаются на:


// prefix (++my_member)
Blabla& operator++(Blabla& orig)
{
  return orig;
}
Re[2]: using namespace XXX vs namespace XXX {
От: SaZ  
Дата: 12.09.13 14:36
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>Как тебе в данный момент удобно, так и предпочтительнее


Предпочтительнее не использовать using в подобных контекстах (в заголовочном файле), поскольку ваш заголовочный файл может включаться в другой заголовочный файл, где такой using будет нежелательным.
Re[4]: using namespace XXX vs namespace XXX {
От: Кодт Россия  
Дата: 12.09.13 15:59
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:

J>Кстате, не заработало для перегрузки operator++ для enum:


Потому что уточнение контекста для определений функций — это забавная штука.
namespace N {
  class C {
    typedef int D;
    D member(D x);
  };
}

N::C::D // здесь контекст ещё самый верхний, namespace :: - поэтому нужно тип квалифицировать полностью
N::C::member // по этой же причине полностью квалифицируем имя члена
( // а вот с этого места контекст - N::C::
  D x
)
{ ... }
// вышли из определения - вернулись к исходному ::

///////////////

auto // чёрт его знает, какой тип
N::C::member
(D x) -> D // в этой строке уже известно про N::C
{ ... }


Опять же,
namespace N
{
  class T {};

  void foo(T); // объявили N::foo(N::T)
}

using namespace N;
void foo(T); // объявили ::foo(N::T)
void foo(T) {...} // определили ::foo(N::T)

int main()
{
  // в поле зрения есть и ::N::foo, и ::foo
  foo(T());
}




Вот такой код работает
http://ideone.com/K3Zq38
#include <iostream>
using namespace std;

namespace N
{
    struct T {};
    T foo(T);
    T& operator++(T&);
}
auto N::foo(T t) -> T { return t; }
auto N::operator++(T& t) -> T& { return t; }

using namespace N;
/* --- если раскомментировать - будут неоднозначности
T foo(T t) { return t; }
T& operator++(T& t) { return t; }
*/

int main() {
    // your code goes here
    T t;
    ++t;
    foo(t);
    cout << "ok\n";
    return 0;
}
Перекуём баги на фичи!
Re[3]: using namespace XXX vs namespace XXX {
От: ArtDenis Россия  
Дата: 12.09.13 16:29
Оценка:
Здравствуйте, SaZ, Вы писали:

SaZ>Предпочтительнее не использовать using в подобных контекстах (в заголовочном файле)


Про заголовочные файлы речь вообще не шла. Читайте внимательнее прежде чем отвечать.
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[5]: using namespace XXX vs namespace XXX {
От: johny5 Новая Зеландия
Дата: 13.09.13 06:49
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Опять же,

К>
К>namespace N
К>{
К>  class T {};

К>  void foo(T); // объявили N::foo(N::T)
К>}

К>using namespace N;
К>void foo(T); // объявили ::foo(N::T)
К>void foo(T) {...} // определили ::foo(N::T)

К>int main()
К>{
К>  // в поле зрения есть и ::N::foo, и ::foo
К>  foo(T());
К>}
К>



Хорошо, это всё так, для функций. А почему (возвращаясь к изначальному вопросу) не так для методов?
Вот к примеру в коде:

// common_header.h
namespace N
{
  struct T
  {
    static void static_method();
    void method();
  };

  void func();
}

// file1.cpp
#include "common_header.h"

using namespace N;
void T::static_method() {}
void T::method() {}
void func() {}


// file2.cpp
#include "common_header.h"
void test()
{
  T t;
  t.method();           // линкуется успешно
  T::static_method();   // линкуется успешно
  func();               // не линкуется
}


Я конечно догадываюсь почему, но хочется увидеть точный, обстоятельный ответ от знающего человека. Я вижу что разница в определении метода в том, что я в любом случае указываю тип класса, а (я догадываюсь что) типы, даже в определении метода, всегда ищутся во всех видимых неймспейсах.

PS: Я таки нашёл главную разницу, свободные функции, объявлённые в namespace, не связываются при их определении без явного указания их неймспейса, а методы связываются. Теперь можно бегать и тыкать носом народ
Re[6]: using namespace XXX vs namespace XXX {
От: Кодт Россия  
Дата: 13.09.13 09:38
Оценка: 4 (1)
Здравствуйте, johny5, Вы писали:

J>Хорошо, это всё так, для функций. А почему (возвращаясь к изначальному вопросу) не так для методов?

J>Я конечно догадываюсь почему, но хочется увидеть точный, обстоятельный ответ от знающего человека. Я вижу что разница в определении метода в том, что я в любом случае указываю тип класса, а (я догадываюсь что) типы, даже в определении метода, всегда ищутся во всех видимых неймспейсах.

Именно: когда встречается квалифицированное имя, T::method, — ищется его объявление. Для чего требуется сперва найти, что такое T и где оно объявлено
А определение функции с неквалифицированным именем — это, одновременно, её объявление в текущем неймспейсе.

Поэтому и получается, что одна функция объявлена в неймспейсе N и не определена, а вторая определена в неймспейсе ::, но не объявлена в file2.cpp, поэтому компилятор её и не искал.

J>PS: Я таки нашёл главную разницу, свободные функции, объявлённые в namespace, не связываются при их определении без явного указания их неймспейса, а методы связываются. Теперь можно бегать и тыкать носом народ


Ну, можно и так сказать. Но дело именно в квалифицированности.
http://ideone.com/zpAycx
#include <iostream>
using namespace std; // пёс с ним, это ideone подвёрстывает

namespace N
{
    namespace M
    {
        void f();
    }//ns M
}//ns N

using namespace N;

void M::f() { cout<<"N::M::f"<<endl; } // пример (частично) квалифицированного имени свободной функции

using namespace M;

int main() {
    f();
    M::f();
    N::M::f();
    return 0;
}
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.