简体   繁体   中英

Defining ostream operator<< for typedef defined in the class

Could anyone provide me a hint how to implement correctly operator<< for MyType in provided code example?

#include <iostream>
#include <map>


template <typename T>
class A {
public:
    typedef std::map<unsigned int, T> MyType;
    MyType data;

    void show();
};

template <typename T>
std::ostream& operator<<(std::ostream& stream, typename A<T>::MyType const& mm)
{
    return stream << mm.size() << "\n";
}

//template <typename T>
//std::ostream& operator<<(std::ostream& stream, std::map<unsigned int, T> const& mm)
//{
//  return stream << mm.size() << "\n";
//}

template <typename T>
void A<T>::show() {std::cout << data;}

int main() {
    A<double> a;

    a.show();

    return 0;
}

Above code does not compile. But when I change definition of operator<< to commented out one, everything works correctly. This is just a (not) working example of a more complicated problem and in reality MyType is much much more nasty. In that simple example I just could easily copy-paste exact definition of MyType from a 'A' class but in more complicated case, when this typedef is depending on antoher typedef... it would be nice just to refer to it. Is there any solution to this problem?

Edit:

Output error from compiler (in general as if operator<< was not defined at all, so when both definitions for operator<< from example are commented out compiler prints same error).

g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++14 -MMD -MP -MF"src/ostreamTest.d" -MT"src/ostreamTest.o" -o "src/ostreamTest.o" "../src/ostreamTest.cpp"
../src/ostreamTest.cpp:27:31: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'MyType' (aka 'map<unsigned int, double>'))
    void A<T>::show() {std::cout << data;}
                       ~~~~~~~~~ ^  ~~~~

Problem is the non-deduced context (thanks PasserBy for the link), which disallows us to find a direct solution.

A workaround might be moving the typedef out of the class, such as this:

template <typename T>
using A_MyType = std::map<unsigned int, T>;

template <typename T>
class A
{
public:
    typedef A_MyType<T> MyType;
    MyType data;

    void show();
};

template <typename T>
std::ostream& operator<<(std::ostream& stream, A_MyType<T> const& mm)
{
    return stream << mm.size() << std::endl;
}

Sure, this works fine for the std::map, if it works for your more complex class – impossible to say without knowing more details...

So I was cooking this as an answer

#include <iostream>
#include <map>

template <typename T>
class A{
public:

    using MyType = std::map<unsigned int, T>;
    MyType data;

    void show();

    friend std::ostream& operator<<(std::ostream& stream, const MyType& mm){
        return stream << mm.size() << "\n";
    }
};

template <typename T>
void A<T>::show(){
    std::cout << data;
}

int main()
{
    A<double> a;
    std::cout << a;
    return 0;
}

But there's a build error quite known that occurs when compiling :
error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

This error often means that the type deduction could not do its job properly (non-deductible context) (cf. Why is template type deduction not working and ostream lvalue error )

Therefore I think that, for the moment, you should find another way around this problem, such way I can't think of for the moment.

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