0

The following code works fine:

Class.h:

#ifndef ClassLoaded
#define ClassLoaded

#include <iostream>

template <class T> class Class{
    public:
        template <class T> friend std::ostream& operator<<(std::ostream& Stream, const Class<T>& Op);
};

#endif

Class.cpp:

#include "Class.h"

template class Class<int>;

template std::ostream& operator<<(std::ostream& Stream, const Class<int>& Op);

template <class T> std::ostream& operator<<(std::ostream& Stream, const Class<T>& Op){
    return(Stream);
}

Main.cpp:

#include "Class.h"
#include <iostream>

using namespace std;

int main(){
    Class<int> Test;

    cout << Test << endl;

    return(0);
}

but the following extended version gives a linker error (unresolved external symbol) and I do more or less understand why. But how to fix it?

Class.h:

#ifndef ClassLoaded
#define ClassLoaded

#include <iostream>

template <class T> class Class{
    public:
        class SubClass{
            public:
                friend std::ostream& operator<<(std::ostream& Stream, const SubClass& Op);
        };

        template <class T> friend std::ostream& operator<<(std::ostream& Stream, const Class<T>& Op);

    private:
        SubClass Member;
};

#endif

Class.cpp:

#include "Class.h"

template class Class<int>;

template std::ostream& operator<<(std::ostream& Stream, const Class<int>& Op);

template <class T> std::ostream& operator<<(std::ostream& Stream, const typename Class<T>::SubClass& Op){
    return(Stream);
}

template <class T> std::ostream& operator<<(std::ostream& Stream, const Class<T>& Op){
    Stream << Op.Member;
    return(Stream);
}

Main.cpp:

#include "Class.h"
#include <iostream>

using namespace std;

int main(){
    Class<int> Test;

    cout << Test << endl;

    return(0);
}

I guess I need an analogue of the lines

template class Class<int>;

template std::ostream& operator<<(std::ostream& Stream, const Class<int>& Op);

for SubClass and also some sort of template version of

friend std::ostream& operator<<(std::ostream& Stream, const SubClass& Op);

but how to do it?

Edit: As this was claimed to be a duplicated of another question: My question here is very specific (see comments below) and is not answered by the quoted questions or even mentioned there.

Mario
  • 123
  • 5
  • On the duplicate question issue: I know that my problem is related to explicit instantiation which is treated in the other question. But my question is more specific as I don't know how to do explicit instantiation in this very setting. – Mario Nov 29 '15 at 19:35
  • Just implement it directly in the class definition. That's the easiest way. – Neil Kirk Nov 29 '15 at 19:35
  • Yes, that would work but I want to keep the definition separated from the interface (i.e. in the Class.cpp file). – Mario Nov 29 '15 at 19:36
  • If you do that then when you explicitly instantiate the template you have to provide a list of all possible types up front. – Neil Kirk Nov 29 '15 at 19:37
  • I understand. This is what I did for the class Class in the working example. But how can I do it for the class SubClass? (for type int for example) – Mario Nov 29 '15 at 19:41
  • Implement the meat of the friend functions in static functions in the class. Then define the friend functions in the header file, and redirect to these static functions that may be implemented in the source file. Getting it to work the "proper" way is too hard. – Neil Kirk Nov 29 '15 at 19:43
  • I know about the workarounds and I agree that it is hard but I want to understand how this works the "proper" way as you put it. That's the whole point of my question. – Mario Nov 29 '15 at 19:46
  • What's the specific linker error? – NietzscheanAI Nov 29 '15 at 20:01
  • Unresolved external symbol: class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class Class::SubClass const &)" (??6@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV01@AEBVSubClass@?$Class@H@@@Z) – Mario Nov 29 '15 at 20:02
  • http://stackoverflow.com/questions/28998697/how-to-properly-declare-a-friend-of-a-nested-class-of-a-template-class – Neil Kirk Nov 29 '15 at 20:28
  • Thank you for the link, that goes in the right direction! But in the second answer it says "So the only way to define this operator== you have declared is to define it separately for each type for which Container is instantiated. This is almost certainly not desirable.". In my case that is exactly what I want but I don't know how to do it. – Mario Nov 29 '15 at 21:41

1 Answers1

0

Just provide the definitions of the template functions in the .hpp files. I believe the following should work:

template <class T> class Class {
    SubClass member;
public:
    class SubClass {
        public:

        friend std::ostream& operator<<(std::ostream& Stream, const Class<T>& Op) {
            return Stream;
        }
    };
}
NietzscheanAI
  • 966
  • 6
  • 16
  • I understand but how to do that in my specific case. What's the correct syntax? – Mario Nov 29 '15 at 19:32
  • Edited to include syntax. – NietzscheanAI Nov 29 '15 at 19:48
  • Yes, this works. But I really want to keep the interface and the implementation separate as I did in the working example. How is the correct syntax for that? Edit: Actually it doesn't work that way, but if you replace Class& Op by SubClass& Op then it does. – Mario Nov 29 '15 at 19:51
  • For templates, keeping interface and implementation separate is fraught with compiler-specific issues. It really is easier to `define at the point of declaration' wherever possible. If you're determined to try and separate things, then maybe moving SubClass (odd choice of name BTW) out from inside Class would make things easier. – NietzscheanAI Nov 29 '15 at 19:54
  • It's called SubClass because it's defined inside of Class. If I move it out of Class it would work as then it would be the same as the working example. But I want to understand how to do it with SubClass being in Class and still separate interface and implementation. I know it's a very specific questions but that's the whole point. – Mario Nov 29 '15 at 19:57