friend declaration declares a non-template function
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);
How to fix gcc warning friend declaration declares a non-template function
The second snippet is ill-formed, because a friend
declaration cannot be a definition of a template specialization. An open clang bug report for accepting this is here.
The first one seems valid to me.
The warning by GCC is annoying, because defining a non-template function as friend is what you want to do here. Unfortunately I don't think there is any way to indicate in code that this is really what you want to do, but you can disable the warning with -Wno-non-template-friend
. According to the documentation it is there for historical reasons, to identify pre-ISO-C++ compatibility issues where the syntax had a different meaning.
You should be aware that the ability to use friend injections of this kind to enable stateful metaprogramming may be considered unintended feature of the language and could maybe (I don't know) be restricted at some point in the future, see this question.
C++ : friend declaration ‘declares a non-template function
There are two different issues in your code, the first is that the friend
declaration (as the warning clearly says, maybe not so clear to understand) declares a single non-templated function as a friend. That is, when you instantiate the template NVector<int,5>
it declares a non-templated function std::ostream& operator<<(std::ostream&,NVector<int,5>)
as a friend. Note that this is different from declaring the template function that you provided as a friend.
I would recommend that you define the friend function inside the class definition. You can read more on this in this answer.
template <typename T, unsigned int TN>
class NVector {
friend std::ostream& operator<<( std::ostream& o, NVector const & v ) {
// code goes here
return o;
}
};
Alternatively you can opt for other options:
- declare the
operator<<
template as a friend (will grant access to any and all instantiations of the template), - declare a particular instantiation of that template as a friend (more cumbersome to write) or
- avoid friendship altogether providing a public
print( std::ostream& )
member function and calling it from a non-friend templatedoperator<<
. I would still opt to befriend the non-template function an provide the definition inside the templated class.
The second issue is that when you want to define an operator outside of the class of the left hand side argument, the operator is a free function (not bound to a class) and thus it should not be qualified:
template<class T, unsigned int TN>
inline std::ostream& operator<<(std::ostream &lhs, const NVector<T, TN> &rhs)
{
/* SOMETHING */
return lhs;
};
friend and template in C++
In friend
declaration operator<<
refers to a non-template function, while its definition says it's a template function; they don't match.
You can define it inline with the friend
declaration (as non-template function):
template<class T>
class Matrix {
... ...
friend std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
... ...
};
Or make the friend
declaration referring to the function template:
// class declaration
template<class T>
class Matrix;
// function declaration
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
// class definition
template<class T>
class Matrix {
... ...
friend std::ostream& operator<< <T>(std::ostream& output, const Matrix<T>& matrix);
... ...
};
// function definition
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
And about the undefined reference error, see Why can templates only be implemented in the header file?
Friend function with a definition - template or non-template?
It is not a template, because its declaration is not that of a template (even though it appears inside a template declaration itself).
[temp.friend] (emphasis mine)
1 A friend of a class or class template can be a function template
or class template, a specialization of a function template or class
template, or a non-template function or class. For a friend function
declaration that is not a template declaration:
if the name of the friend is a qualified or unqualified template-id, the friend declaration refers to a specialization of a function
template, otherwise,if the name of the friend is a qualified-id and a matching non-template function is found in the specified class or namespace,
the friend declaration refers to that function, otherwise,if the name of the friend is a qualified-id and a matching function template is found in the specified class or namespace, the friend
declaration refers to the deduced specialization of that function
template ([temp.deduct.decl]), otherwise,the name shall be an unqualified-id that declares (or redeclares) a non-template function.
[ Example:
template<class T> class task;
template<class T> task<T>* preempt(task<T>*);
template<class T> class task {
friend void next_time();
friend void process(task<T>*);
friend task<T>* preempt<T>(task<T>*);
template<class C> friend int func(C);
friend class task<int>;
template<class P> friend class frd;
};
Here, each specialization of the task class template has the function
next_time
as a friend; becauseprocess
does not have explicit
template-arguments, each specialization of the task class template has
an appropriately typed functionprocess
as a friend, and this friend
is not a function template specialization; because the friend
preempt
has an explicit template-argumentT
, each specialization
of thetask
class template has the appropriate specialization of the
function templatepreempt
as a friend; and each specialization of
thetask
class template has all specializations of the function
templatefunc
as friends. Similarly, each specialization of the
task
class template has the class template specialization
task<int>
as a friend, and has all specializations of the class
templatefrd
as friends. — end example ]
While examples are non-normative, the one in the quote clarifies the intent of the preceding normative text. Since the friend operator declaration is not a template declaration, the text in bold applies. It therefore declares a non-template function.
define non-template function outside a templated class
In the first program
template<typename T>
class cl
{
private :
T val;
public:
cl()= default;
explicit cl(T v) : val(std::move(v)) {}
friend void non_template_friend(cl m);
};
template <typename T>
void non_template_friend(cl<T> m) { std::cout << m.val << std::endl;}
You declared a non-template friend funcrion but then you declared and defined a template function with the same name/
A non-template friend function declaration means thatf you have to provide a set of overloaded non-template functions for specializations of the template class/
Here is a demonstrative program.
#include <iostream>
template<typename T>
class cl
{
private :
T val;
public:
cl()= default;
explicit cl(T v) : val(std::move(v)) {}
friend void non_template_friend(cl m) ;
};
void non_template_friend( cl<int> m) { std::cout << m.val << std::endl;}
void non_template_friend( cl<double> m) { std::cout << m.val << std::endl;}
int main()
{
cl<int> c(10);
non_template_friend(c);
cl<double> c2( 20.2 );
non_template_friend(c2);
return 0;
}
The program output is
10
20.2
That is in a template class a non-template friend function declaration is in fact declares a set of overloaded non-template functions.
Related Topics
Different Ways of Initializing an Object in C++
Convert Const Char* to Wstring
Benefits of Using Reserve() in a Vector - C++
How to Sleep or Pause a Pthread in C on Linux
Question About a Function Definition (Three Dots in Parameters..)
How to Initialize All Elements in an Array to the Same Number in C++
How Can a C++ Binary Replace Itself
What's the Time Complexity of Iterating Through a Std::Set/Std::Map
Incompatible with Parameter of Type "Lpcwstr"
Copying Derived Entities Using Only Base Class Pointers, (Without Exhaustive Testing!) - C++
What Is a Good Easy to Use Profiler for C++ on Linux
One Way of Eliminating C4251 Warning When Using Stl-Classes in the Dll-Interface
Optimize Template Replacement of a Switch
Writing Python Bindings for C++ Code That Use Opencv
Inheriting Private Members in C++