gcc не может скомпилировать определение оператора с префиксным пространством имен - PullRequest
8 голосов
/ 21 января 2011

У меня есть операторы, объявленные для класса my_type в пространстве имен my_namespace.

namespace my_namespace {
 class my_type
 {
  friend std::ostream& operator << (std::ostream& out, my_type t);
 }
}

Я пытаюсь определить эти операторы в файле реализации, но когда я пишу что-то подобное

std::ostream& my_namespace::operator << (std::ostream& out, my_type t)
{
 out << t;
 return out;
}

Я получаю сообщение об ошибке

error: ... operator should have been declared inside 'my_namespace'

Когда я изменяю его на

namespace my_namespace {
    std::ostream& operator << (std::ostream& out, my_type t)
    {
     out << t;
     return out;
    }
}

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

1020 * добавлен *

file.h

#ifndef A_H
#define A_H

#include <iosfwd>

namespace N
{
 class A
 {
  friend std::ostream& operator << (std::ostream& out, A& obj);
 };
}

#endif

file.cpp

#include "file.h"
#include <iostream>

std::ostream& N::operator << (std::ostream& out, N::A& obj)
{
 return out;
}

int main() {}

вот полный пример. Это хорошо работает на VS2010, но дает вышеупомянутую ошибку на gcc 4.4.5.

добавлен

хмм ... да, этот работает

namespace N
{
    class A
    {
        friend std::ostream& operator << (std::ostream& out, A& obj);
    };
    std::ostream& operator << (std::ostream& out, A& obj);
}

Я всегда думал, что с точки зрения видимости объявление оператора в классе - это то же самое, что объявление вне класса ... похоже, что это не так. Спасибо.

Большое спасибо заранее.

Ответы [ 2 ]

9 голосов
/ 21 января 2011

Сообщение об ошибке говорит само за себя. Вы можете сохранить определение своей функции в файле реализации, но вам нужно сначала объявить его в пространстве имен:

namespace my_namespace {
    std::ostream& operator << (std::ostream& out, my_type t);
}

Стандарт C ++ довольно ясно говорит об этом:

7.3.1.2 / 3:

Каждое имя, впервые объявленное в пространстве имен, является членом этого пространства имен. Если объявление друга в нелокальном классе сначала объявляет класс или функцию, класс или функция друга является членом самого внутреннего окружающего пространства имен. Имя друга не может быть найдено при простом поиске по имени, пока не будет предоставлено соответствующее объявление в этой области пространства имен (до или после объявления класса, предоставляющего дружбу). Если вызывается функция друга, ее имя может быть найдено с помощью поиска имен, который рассматривает функции из пространств имен и классов, связанных с типами аргументов функции (3.4.2). При поиске предварительного объявления класса или функции, объявленной в качестве друга, и когда имя класса или функции друга не является ни квалифицированным именем, ни идентификатором шаблона, области действия за пределами самой внутренней охватывающей области пространства имен не рассматриваются. .

Следующая ссылка упрощает и добавляет несколько примеров: http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr043.htm

Так что я бы сказал, что gcc здесь не так. . Соответствующее предложение выглядит следующим образом: " Имя друга не найдено простым поиском имени, пока не будет предоставлено соответствующее объявление в этой области пространства имен (до или после объявления класса, предоставляющего дружбу) .

1 голос
/ 21 января 2011

Объявления ссылаются на набор других имен и вводят одно новое имя; это новое имя не должно квалифицироваться идентификатором пространства имен, а объявление должно находиться внутри блока пространства имен, в котором должно быть объявлено новое имя.

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

...