BR41N-FCK
BR41N-FCK

Reputation: 766

Overloading operator<< for a member structure defined in a template structure

Hello dear StackOverflowers!

I am having trouble with a template structure which comprises another (but non-template) structure.

Here's the thing:

  1. Structure B is non-template and is defined inside a template structure A.

  2. Strcure B is "protected" because it exists only for the purposes of structure A and no-one and nothing else shall use it outside of structure A.

  3. There's an overload of operator<< for structure B, so that objects of type B can be sent to the standard output "cout << B_type_object;" (and it's A's friend so that it can access B which is protected).

  4. The aforementioned printing of B objects is done only by methods defined in A (because of "2.").

  5. As long as both structures are non-template everything works like a charm.

  6. The moment A is a template I get an error message (provided in the code section).

Here is the working code (where A is not template):

#include <iostream>
#include <string>

struct A
{

protected:
    struct B
    {
        std::string something;

        B& operator= (const std::string&& rhs)
        {
            this->something = std::move(rhs);
            return *this;
        }
    };

    B B_object;

    friend std::ostream& operator<< (std::ostream& output, const typename A::B& ob);

public:
    void method ()
    {
        B_object = "This is text.";
        //No error here
        std::cout << B_object;
    }
};



std::ostream& operator<< (std::ostream& output, const typename A::B& ob)
{
    output << ob.something;
    return output;
}



int main(int argc, const char * argv[])
{
    A obj;
    obj.method();

    return 0;
}

This is the code which doesn't work

#include <iostream>
#include <string>

template <typename T>
struct A
{
    T variable;

protected:
    struct B
    {
        std::string something;

        B& operator= (const std::string&& rhs)
        {
            this->something = std::move(rhs);
            return *this;
        }
    };

    B B_object;

    template <typename X> friend std::ostream& operator<< (std::ostream& output, typename A/*<X>*/::B& ob);

public:
    void method ()
    {
        B_object = "This is text.";

        //ERROR: Invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'A<int>::B')
        std::cout << B_object;
    }
};



template <typename X>
std::ostream& operator<< (std::ostream& output, typename A<X>::B& ob)
{
    output << ob.something;
    return output;
}



int main(int argc, const char * argv[])
{
    A<int> obj;
    obj.method();

    return 0;
}

Upvotes: 1

Views: 185

Answers (1)

gexicide
gexicide

Reputation: 40058

Just declare the operator inline in B, then it works:

...
struct B
{
    std::string something;

    B& operator= (const std::string&& rhs)
    {
        this->something = std::move(rhs);
        return *this;
    }

    friend std::ostream& operator<< (std::ostream& output, const typename A<T>::B& ob)
    {
        output << ob.something;
        return output;
    }
};
...

This has also the advantage that your are not friending any operator<< of any A<X>. In your example, the operator taking A<string>::B would also be a friend of A<int>::B. For a more in-depth explanation, see this answer: https://stackoverflow.com/a/4661372/36565

Upvotes: 2

Related Questions