friend declaration declares a non-template function

40,985

Solution 1

It sounds like you want to change:

friend ostream& operator << (ostream& out, const Base<T>& e);

To:

template<class T>
friend ostream& operator << (ostream& out, const Base<T>& e);

Solution 2

Gcc is rightly warning you. Despite it's appearances (it takes Base argument), it is not a function template.

Your class definition has a non-template declaration of the friend function (without the template), but the friend function definition later on is a function template (i.e. starts with template..).

Also your operator<< takes a Base *. This is not correct. It should be Base const & to retain it's built-in semantics

Probably you are looking at something as below:

template <typename T> 
class Base { 
  public: 
    friend ostream& operator << (ostream &out, Base<T> const &e){
       return out;
    }; 
}; 

int main(){
   Base<int> b;
   cout << b;
}

If you want fully templated, then this is probably what you want. But I am not sure how much useful this is over the previous one. Since the lookup involves ADL, you will never be able to resolve to any condition where T is not equal to U (as long as the call is from a context not related to this class e.g. from 'main' function)

template <typename T>  
class Base {  
  public:  
    template<class U> friend ostream& operator << (ostream &out, Base<U> const &e){ 
       return out; 
    };  
};

int main(){ 
   Base<int> b; 
   cout << b; 
} 

Solution 3

Probably what you are looking for is:

template <typename T>
class Base;

template <typename T>
ostream& operator<< (ostream &, const Base<T>&);

template <typename T>
class Base
{
  public:
    template<>
    friend ostream& operator << <T>(ostream &, const Base<T> &);
};

template <typename T>
ostream& operator<< ( ostream &out, const Base<T>& e )
{
    return out << e->data;
}

This friends only a single instantiation of the template, the one where the operator's template parameter matches the class's template parameter.

UPDATE: Unfortunately, it's illegal. Both MSVC and Comeau reject it. Which raises the question of why the original error message suggested pretty much EXACTLY this approach.

Solution 4

changing

friend ostream& operator << (ostream& out, const Base<T>& e);

to

friend ostream& operator << <T>(ostream& out, const Base<T>& e);

should work as well--I just solved an identical problem in this way.

Share:
40,985
mike_b
Author by

mike_b

Updated on March 04, 2020

Comments

  • mike_b
    mike_b about 4 years

    I have a base Class akin to the code below. I'm attempting to overload << to use with cout. However, g++ is saying:

    base.h:24: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, Base<T>*)’ declares a non-template function
    base.h:24: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
    

    I've tried adding <> after << in the class declaration / prototype. However, then I get it does not match any template declaration. I've been attempting to have the operator definition fully templated (which I want), but I've only been able to get it to work with the following code, with the operator manually instantiated.

    base.h

    template <typename T>
    class Base {
      public:
        friend ostream& operator << (ostream &out, Base<T> *e);
    };
    

    base.cpp

    ostream& operator<< (ostream &out, Base<int> *e) {
        out << e->data;
    return out;
    }
    

    I want to just have this or similar in the header, base.h:

    template <typename T>
    class Base {
      public:
        friend ostream& operator << (ostream &out, Base<T> *e);
    };
    
    template <typename T>
    ostream& operator<< (ostream &out, Base<T> *e) {
        out << e->data;
    return out;
    }
    

    I've read elsewhere online that putting <> between << and () in the prototype should fix this, but it doesn't. Can I get this into a single function template?

  • mike_b
    mike_b over 13 years
    This definitely won't work. Besides giving employee.cpp:32: error: ‘T’ was not declared in this scope, even after making it a template in either .h or .cpp file, it won't work due to undefined symbols during linking. In addition I still get the warning. I want it to be like a normal template defined in a header file.
  • mike_b
    mike_b over 13 years
    So I didn't believe you, but this works. However, I can't use T because it shadows the already existing T of the class template.
  • asdfjklqwer
    asdfjklqwer over 13 years
    Does GCC give you a warning about the shadowing?
  • mike_b
    mike_b over 13 years
    Yes, GCC gave a warning about shadowing. I replaced T with Y and that resolved it. error: shadows template parm ‘class T’
  • asdfjklqwer
    asdfjklqwer over 13 years
    Interesting. I tested my answer with Visual Studio which doesn't have a problem with the shadowing. But I can see why GCC might spit out a warning... like you said, replacing T with another template parameter will eliminate the shadowing. Btw Ben, your solution doesn't compile in MSVC.
  • Bruce Armstrong
    Bruce Armstrong over 13 years
    I completely missed the class being Base at that point. Should just be T, but I see more complete answers, so I'll mod them up.
  • Ben Voigt
    Ben Voigt over 13 years
    Mine is also rejected by Comeau. Annoying because it's exactly the right syntax for what the OP wanted, but it apparently falls afoul of a restriction on friend functions. +1 to you.
  • Ben Voigt
    Ben Voigt over 13 years
    Well, use of the << operator wouldn't ever find any instantiation with U != T. A direct call potentially could though, which would just be really weird. It would only matter if operator << for Base<U> accessed a global variable of type Base<T>.
  • Chubsdad
    Chubsdad over 13 years
    @Ben Voigt: Added the part 'as long as the call is from a context not related to this class e.g. from 'main' function'. Hope it is clearer now
  • Michael Kristofik
    Michael Kristofik over 13 years
    The C++ FAQ says that the friend line in the class declaration should have a <>, not a <T>.
  • Michael Kristofik
    Michael Kristofik over 13 years
    And apparently you're not supposed to need the template<> line before it. (No access to compiler right now, haven't tried it.)
  • Tom Artiom Fiodorov
    Tom Artiom Fiodorov over 10 years
    So operator<<(ostream&, const Base<T>&) becomes a friend of Base<S> even when S and T are distinct? I think the answer should clarify this.
  • Gauthier
    Gauthier over 7 years
    Maybe add how to define the friend function outside the class definition, for completeness?
  • M.M
    M.M almost 6 years
    I believe the original error message is suggesting public: friend ostream& operator << <>(ostream &, const Base<T> &);