简体   繁体   中英

Overloading operator outside template struct

I have the following code:

#include <iostream>
#include <stdio.h>
using namespace std;

template <class F>
struct CMPLX {

    F Re, Im;

    struct _printnice {
        F Re, Im;
        string sep;
        _printnice(const F& Re, const F& Im, const string& sep) : Re(Re), Im(Im), sep(sep) {}
    };

    CMPLX <F> (F Re, F Im) : Re(Re), Im(Im) {}

    _printnice PrintNice(const string& sep="\t"){
        return _printnice(Re, Im, sep);
    }

};

template<class F>
ostream& operator << (ostream& os, const CMPLX<F> c){
    cout << c.Re << " + " << c.Im << "i";
}

template<class F>
ostream& operator << (ostream& os, const CMPLX<F> :: _printnice p){
    cout << p.Re << p.sep << p.Im;
}

int main(){
    CMPLX<float> c(2.0,1.0);
    cout << c << endl;
    cout << c.PrintNice() << endl;

}

I introduce a sub-struct _printnice in order to overload the operator << and have differently-formatted output of my CMPLX class. However, this throws an error expected unqualified-id before 'p' and I don't know how to solve this (my knowledge on templates is very limited).

I try to change the 2nd definition of << to the following which works, but I have to specify the type, which is frowned-upon:

ostream& operator << (ostream& os, const CMPLX <float> :: _printnice p){
    cout << p.Re << p.sep << p.Im;
}

There are two issues with your approach. The first is that _printnice is a dependent name and as such you need to add an extra typename . If that were fixed you would end up with:

template<class F>
ostream& operator << (ostream& os, typename CMPLX<F>::_printnice const & p)

The problem with this code, as Dietmar pointed out in a previous answer, is that F is in a non deducible context, and this will fail.

One simple solution is to define the operator inside the scope of the _printnice code, where the typename :

template <class F>
struct CMPLX {
   //...
   struct _printnice {
      friend std::ostream& operator<<( std::ostream& o, _printnice const & p ) {
         // print here
         return o;
      }
   }
   //...
};

Inside the definition of _printnice , the type is known to be a type and thus the typename is no longer required. The overloaded operator<< will be found by Argument Dependent Lookup, and because it refers to this particular instantiation of the type, there is no template arguments to deduce.

In the function:

template <typename F>
std::ostream& operator<<( std::ostream& os, CMPLX<F>::_printnice p);

F is not not in a deducible context. (See §14.8.2.5.)

NB. This is not a answer. David answered it already. FWIW, just fixed a few things so it can compile & runable under gcc 4.72.

#include <iostream>
#include <stdio.h>
using namespace std;

template <class F>
struct CMPLX {

    F Re, Im;

    struct _printnice {

        F Re, Im;
        string sep;
        _printnice(const F& Re, const F& Im, const string& sep) : Re(Re), Im(Im), sep(sep) {}

        friend ostream& operator << (ostream& os, const _printnice& p){
            cout << p.Re << p.sep << p.Im;
            return os;
        }
    };

    CMPLX <F> (F Re, F Im) : Re(Re), Im(Im) {}

    _printnice PrintNice(const string& sep="\t"){
        return _printnice(Re, Im, sep);
    }

};

template<class F>
ostream& operator << (ostream& os, const CMPLX<F> c){
    cout << c.Re << " + " << c.Im << "i";
    return os;
}

int main() {
    CMPLX<float> c(2.0,1.0);
    cout << c << endl;
    cout << c.PrintNice() << endl;
}

//result
/*
2 + 1i
2       1
*/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM