реализация или определение класса или функции, объявленной внутри безымянного / анонимного пространства имен - PullRequest
4 голосов
/ 23 июля 2011

Разрешено ли определять реализацию функции или членов класса вне безымянного (анонимного) пространства имен, в котором они были определены.Мой компилятор принимает это, но я хочу быть уверен, что это допустимо, например,

////////////////
// foo.cpp 

namespace {
 struct X
 {
 void foo(int x);
 };
}

// Is this legal?
void X::foo(int x)
{
}

. Причина в том, что я хотел бы избежать ненужных отступов, налагаемых нашим форматом uncrustify

Ответы [ 4 ]

4 голосов
/ 23 июля 2011

Это на самом деле ничем не отличается от следующего, что совершенно законно:

namespace ns {
    struct s {
        void f();
    };
}

using namespace ns;

void s::f() { }

Имена из именованного пространства имен заносятся в глобальное пространство имен и, таким образом, для них могут быть предоставлены определения. Единственная разница с безымянным пространством имен состоит в том, что у него нет имени (на самом деле, у него есть какое-то уникальное, невыразимое имя), и using namespace неявно.

0 голосов
/ 22 декабря 2016

Это допустимо в вашем сценарии, но в одном случае это вызовет неоднозначную ошибку компилятора.

Если есть другой класс в X.h:

// X.h
struct X
{
    void foo(int x) { }
};

А в foo.cpp нужно использовать X, определенный в X.h

////////////////
// foo.cpp 
#include "X.h"

namespace {
    struct X
    {
        void foo(int x);
    };

    // use the X declared in anonymous namespace
    void test()
    {
        X x;
        x.foo(3);
    }
}

// reference to 'X' is ambiguous
void X::foo(int x)
{
}

void otherFunction()
{
    // Use struct X in X.h
    ::X x;
    x.foo(3);
}

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

0 голосов
/ 23 июля 2011

Да.Это совершенно законно.Отличие безымянного пространства имен в том, что содержимое пространства имен доступно только в объявленном им файле.Если он находится в файле .h, он будет добавлен во все последующие файлы .cpp, и каждый файл .cpp будет иметь уникальную копию содержимого namespace.

Фактически этолучший способ объявить глобальную переменную static.Теперь посмотрим, какую разницу это будет иметь:

namespace {
 struct X
 {
   void foo(int x);
 };
 int i;  // declare this global variable
}

Если вы поместите этот код в файл заголовка, то, где бы этот файл заголовка не был #include ed, все эти файлы .cpp будут иметьдругая копия int i; внутри них.Изменение значения i в одном файле .cpp не повлияет на другой файл .cpp.

Более того, оно не даст ошибку компоновщика для нескольких определений, так как оно в безымянном namespace.

Редактировать : Чтобы оценить его больше, определите пространство имен следующим образом:

// x.h
namespace
{
  struct X
  {
    void foo(int x)
    {
      static int c;  // static inside the function
      cout<<"a = "<<(c++)<<endl;
    }
  };
}

Теперь #include этот заголовочный файл в 2 разных .cpp файлах.В обоих из них попробуйте вызвать foo() с объектом X.Будет напечатано:

a = 0
a = 0

Это означает, что X::foo() в обоих .cpp файлах отличаются .Если вы дадите имя namespace и повторите то же самое, будет выведено

a = 0
a = 1

Таким образом, безымянный namespace создает разные копии для каждой единицы перевода.

0 голосов
/ 23 июля 2011
#include <iostream>
using namespace std;

namespace
{
  struct X
  {
     X(int);
     int x_;
  };
}

X::X(int x) : x_(x) {}

int main()
{
   X x(5);

   cout << x.x_ << "\n";
   return 0;
}

Компилирует (и запускает) под gcc 4.6.0

...