friend declaration declares a non-template function
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.
mike_b
Updated on March 04, 2020Comments
-
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 over 13 yearsThis 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 over 13 yearsSo I didn't believe you, but this works. However, I can't use
T
because itshadows
the already existingT
of the class template. -
asdfjklqwer over 13 yearsDoes GCC give you a warning about the shadowing?
-
mike_b over 13 yearsYes, GCC gave a warning about shadowing. I replaced T with Y and that resolved it.
error: shadows template parm ‘class T’
-
asdfjklqwer over 13 yearsInteresting. 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 over 13 yearsI 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 over 13 yearsMine 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 over 13 yearsWell, use of the
<<
operator wouldn't ever find any instantiation withU != T
. A direct call potentially could though, which would just be really weird. It would only matter ifoperator <<
forBase<U>
accessed a global variable of typeBase<T>
. -
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 over 13 years
-
Michael Kristofik over 13 yearsAnd 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 over 10 yearsSo 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 over 7 yearsMaybe add how to define the friend function outside the class definition, for completeness?
-
M.M almost 6 yearsI believe the original error message is suggesting
public: friend ostream& operator << <>(ostream &, const Base<T> &);