@ Jean-MichaëlCelerier Тип decl гарантирует, что этот оператор используется только при наличии t :: print. В противном случае он попытался бы скомпилировать тело функции и выдать ошибку компиляции.

у небольшую матричную библиотеку на C ++ для матричных операций. Однако мой компилятор жалуется, где раньше этого не было. Этот код оставлялся на полке в течение 6 месяцев, и между тем я обновил свой компьютер с debian etch до lenny (g ++ (Debian 4.3.2-1.1) 4.3.2), однако у меня та же проблема в системе Ubuntu с тем же g ++ ,

Вот соответствующая часть моего класса матрицы:

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix);
    }
}

И «реализация»:

using namespace Math;

std::ostream& Matrix::operator <<(std::ostream& stream, const Matrix& matrix) {

    [...]

}

Это ошибка, выданная компилятором:

matrix.cpp: 459: ошибка: 'std :: ostream & Math :: Matrix :: operator << (std :: ostream &, const Math :: Matrix &)' должен принимать ровно один аргумент

Я немного сбит с толку этой ошибкой, но опять же мой C ++ стал немного ржавым после того, как я много работал за те 6 месяцев. :-)

Ответы на вопрос(5)

ъекта, который имеет T :: print (std :: ostream &) const; член.

template<class T>
auto operator<<(std::ostream& os, const T& t) -> decltype(t.print(os), os) 
{ 
    t.print(os); 
    return os; 
} 
 jotik12 мар. 2016 г., 15:29
На самом деле, похоже, это работает и в C ++ 11.
 Jean-Michaël Celerier08 мар. 2017 г., 21:16
ты не можешь просто вернутьсяstd::ostream&, так как это тип возврата в любом случае?
 QuentinUK17 мая 2016 г., 01:30
@barney Это может быть в вашем собственном пространстве имен вместе с классами, которые его используют.
 QuentinUK12 мар. 2017 г., 11:43
@ Jean-MichaëlCelerier Тип decl гарантирует, что этот оператор используется только при наличии t :: print. В противном случае он попытался бы скомпилировать тело функции и выдать ошибку компиляции.
 barney16 мая 2016 г., 08:08
интересное решение! Один вопрос - где этот оператор должен быть объявлен, как в глобальной области видимости? Я предполагаю, что это должно быть видимым для всех типов, которые могут быть использованы для его шаблонизации?

мне нравится использовать для этого определения друзей:

namespace Math
{
    class Matrix
    {
    public:

        [...]

        friend std::ostream& operator<< (std::ostream& stream, const Matrix& matrix) {
            [...]
        }
    };
}

Функция будет автоматически нацелена на окружающее пространство именMath (даже если его определение находится в области действия этого класса), но оно не будет видимым, если вы не вызовете operator << с объектом Matrix, который сделает поиск по аргументам зависимым, чтобы найти это определение оператора. Иногда это может помочь с неоднозначными вызовами, поскольку он невидим для типов аргументов, отличных от Matrix. При написании его определения вы также можете напрямую ссылаться на имена, определенные в Matrix, и на саму Matrix, не квалифицируя имя с некоторым возможно длинным префиксом и предоставляя такие параметры шаблона, какMath::Matrix<TypeA, N>.

 Beginner23 мар. 2018 г., 08:49
Для чего нужен спецификатор друга?

operator << для всех классов, полученных изstd::ostream обращаться сMatrix класс (и не перегружен<< заMatrix class), имеет смысл объявить функцию перегрузки вне пространства имен Math в заголовке.

Используйте функцию друга, только если функциональность не может быть достигнута через общедоступные интерфейсы.

Matrix.h

namespace Math { 
    class Matrix { 
        //...
    };  
}
std::ostream& operator<<(std::ostream&, const Math::Matrix&);

Обратите внимание, что перегрузка оператора объявляется вне пространства имен.

Matrix.cpp

using namespace Math;
using namespace std;

ostream& operator<< (ostream& os, const Matrix& obj) {
    os << obj.getXYZ() << obj.getABC() << '\n';
    return os;
}

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

math.h

namespace Math {
    class Matrix {
        public:
            friend std::ostream& operator<<(std::ostream&, const Matrix&);
    };
}

Вам нужно заключить определение функции в блок пространства имен, а не простоusing namespace Math;.

Matrix.cpp

using namespace Math;
using namespace std;

namespace Math {
    ostream& operator<<(ostream& os, const Matrix& obj) {
        os << obj.XYZ << obj.ABC << '\n';
        return os;
    }                 
}
Решение Вопроса

friend, Это не член класса. Вы должны удалитьMatrix:: от реализации.friend означает, что указанная функция (которая не является членом класса) может обращаться к закрытым переменным-членам. То, как вы реализовали функцию, похоже на метод экземпляра дляMatrix класс, который не так.

 Mark Lakata01 мая 2015 г., 23:58
Почемуoperator<< должны быть в пространстве именMath? Кажется, это должно быть в глобальном пространстве имен. Я согласен, что мой компилятор хочет, чтобы он был в пространстве именMath, но это не имеет смысла для меня.
 David Rodríguez - dribeas23 мар. 2009 г., 22:35
И вы также должны объявить это внутри пространства имен Math (не только с использованием пространства имен Math).

Чтобы добавить к Mehrdad ответ,

namespace Math
{
    class Matrix
    {
       public:

       [...]


    }   
    std::ostream& operator<< (std::ostream& stream, const Math::Matrix& matrix);
}

В вашей реализации

std::ostream& operator<<(std::ostream& stream, 
                     const Math::Matrix& matrix) {
    matrix.print(stream); //assuming you define print for matrix 
    return stream;
 }
 kal24 янв. 2009 г., 21:30
Ответ Mehrdad не содержал никакого фрагмента кода, поэтому я просто добавил, что может сработать, переместив его за пределы класса в самом пространстве имен.
 kal24 янв. 2009 г., 21:28
Я не понимаю, почему это голосование против, это проясняет, что вы можете объявить оператора как находящегося в пространстве имен, а не как друга, и как вы можете объявить этого оператора.
 David Rodríguez - dribeas23 мар. 2009 г., 22:45
Мало того, что это вне класса, но это правильно определеновнутри пространство имен Math. Кроме того, у него есть дополнительное преимущество (возможно, не для матрицы, но с другими классами), что «печать» может быть виртуальной, и, таким образом, печать будет происходить на самом производном уровне наследования.
 Matthias van der Vlies24 янв. 2009 г., 21:32
Я понимаю вашу точку зрения, я только посмотрел на ваш второй фрагмент. Но теперь я вижу, что вы вывели оператора из класса. Спасибо за предложение.

Ваш ответ на вопрос