How to enable a friend class's friend function access its private members directly in C++

Viewed 77

I'm writing a sparse matrix class, and I want to output the sparse matrix by overloading operator<<. I'm wondering how to enable a friend function of SMatrix (operator<<) directly (not by some interface) access private data members of TriTuple? Note that SMatrix is meanwhile a friend class of TriTuple. See code as follows.

// tri-tuple term for sparse matrix by the form <row, col, value>
template<typename T>
class TriTuple {
    template<typename U> friend class SMatrix;
    // enable friend of SMatrix access private members of TriTuple
    // declaring like this? feasible in VS2019, but not in gcc
    template<typename U>
    friend std::ostream& operator<<(std::ostream& os, const SMatrix<U>& M);
private:
    size_t _row, _col;
    T _val;
public:
    //...
};

// sparse matrix
template<typename T>
class SMatrix {
    template<typename U>
    friend std::ostream& operator<<(std::ostream& os, const SMatrix<U>& M);
private:
    size_t _rows, _cols;// # of rows & columns
    size_t _terms;      // # of terms
    TriTuple<T>* _arr;  // stored by 1-dimensional array
    size_t _maxSize;
public:
    //...  
};

template<typename U>
std::ostream& operator<<(std::ostream& os, const SMatrix<U>& M)
{
    M.printHeader();
    for (size_t i = 0; i < M._terms; ++i) {
        os << M._arr[i]._row << "\t\t" << M._arr[i]._col << "\t\t" << M._arr[i]._val << '\n';
    }
    return os;
}

It can successfully compile & run in VS2019 (likely C++17), but failed to compile in gcc (currently only c++11 is available). Is that c++ standard version's problem? (It refers "ISO C++ forbids declaration of ..." ) And how should I improve the declarations? See error messages in following picture. gcc error_msg Thank you awesome guys in advance :-)

2 Answers

This error is related to forward declaration of the class SMatrix. Just try to forward declare

template<typename T>
class SMatrix;

above the TriTuple.

Check it on godbolt

Also there is no check for empty matrix in the operator<<. I suggest you to use -fsanitize=undefined -fsanitize=address for gcc.

[class.friend]/p11:

If a friend declaration appears in a local class ([class.local]) and the name specified is an unqualified name, a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope. For a friend function declaration, if there is no prior declaration, the program is ill-formed. For a friend class declaration, if there is no prior declaration, the class that is specified belongs to the innermost enclosing non-class scope, but if it is subsequently referenced, its name is not found by name lookup until a matching declaration is provided in the innermost enclosing non-class scope.

You need to provide the definition for SMatrix or at least forward-declare it before referencing it:

template <typename U>
class SMatrix;
Related