friend declaration declares a non-template function

F

fdmfdmfdm

I have the following code:

#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace std;
template <class T>
class Stack{
public:
enum{DefaultStack = 10, EmptyStack = -1};
Stack();
Stack(int);
~Stack();
void push(const T&);
T pop();
T topNoPop() const;
bool empty() const;
bool full() const;
friend ostream& operator<<(ostream& os, const Stack<T>& s);
private:
T* elements;
int top;
int size;
void allocate(){
elements = new T[size];
top = EmptyStack;
}
void msg(char m[]) const{
cout << "*** " << m << " ***" << endl;
}


};

template<class T>
ostream& operator<<(ostream& os, const Stack<T>& s)

{
s.msg("Stack contents:");
int t = s.top;
while (t > s.EmptyStack)
cout << s.elements[t--] << endl;
return os;
}

template<class T>
Stack<T>::Stack(){
size = DefaultStack;
allocate();
}

template<class T>
Stack<T>::Stack(int s){
if (s < 0)
s *= -1;
else if (s == 0)
s = DefaultStack;
size = s;
allocate();
}

template<class T>
Stack<T>::~Stack(){
delete[] elements;
}

template<class T>
void Stack<T>::push(const T& e){
assert(!full());
if (!full())
elements[++top] = e;
else
msg("Stack full!");
}

template<class T>
T Stack<T>::pop(){
assert(!empty());
if (!empty())
return elements[top--];
else{
msg("Stack empty!");
T dummy_value;
return dummy_value; //return arbitrary value
}
}

template<class T>
T Stack<T>::topNoPop() const{
assert(top > EmptyStack);
if (!empty())
return elements[top];
else{
msg("Stack Empty!");
T dummy_value;
return dummy_value;
}
}

template<class T>
bool Stack<T>::empty() const{
return top <= EmptyStack;
}

template<class T>
bool Stack<T>::full() const{
return top + 1 >= size;
}


int main(){

Stack<char> cStack(20);

cout << cStack << endl; //empty stack


cout << "pushing A, B" << endl;
cStack.push('A');
cStack.push('B');
cout << cStack << endl; //BA
return 0;
}


When I compile with g++, there is error like:

stack.cpp:18: warning: friend declaration `std::eek:stream&
operator<<(std::eek:stream&, const Stack<T>&)' declares a non-template
function
stack.cpp:18: 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
/tmp/ccrvlcDf.o(.text+0x13f): In function `main':
: undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Stack<char> const&)'
/tmp/ccrvlcDf.o(.text+0x1b8): In function `main':
: undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Stack<char> const&)'
collect2: ld returned 1 exit status


I think it's totally legal to make a friend function inside a template
class declaration, why there is an error like this?

Thank you.
 
I

Ian Collins

I have the following code:
When I compile with g++, there is error like:

stack.cpp:18: warning: friend declaration `std::eek:stream&
operator<<(std::eek:stream&, const Stack<T>&)' declares a non-template
function
stack.cpp:18: 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
/tmp/ccrvlcDf.o(.text+0x13f): In function `main':
: undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Stack<char> const&)'
/tmp/ccrvlcDf.o(.text+0x1b8): In function `main':
: undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Stack<char> const&)'
collect2: ld returned 1 exit status

I think it's totally legal to make a friend function inside a template
class declaration, why there is an error like this?
It is, but gcc is kind enough to tell you that your declaration is a
non-template function in the context it is declared (Stack<T> being
whatever instance of the template is being instantiated).

Follow the compiler's advice and all will be well, either

template <class T> class Stack;

template<class T>
ostream& operator<<(ostream& os, const Stack<T>& s)

{
s.msg("Stack contents:");
int t = s.top;
while (t > s.EmptyStack)
cout << s.elements[t--] << endl;
return os;
}

Before the class, with

friend ostream& operator<< <>(ostream& os, const Stack<T>& s);

in the class, or simply inline the function in the class declaration.

Note you should be using const char* m (or const std::string& ) as the
parameter for your msg member.
 
F

fdmfdmfdm

Sorry, I didn't get you. Actually if I write this friend function in
class defintition, it won't have any problem. But why when I define it
out of the class, the compiler complains?

I have the following code:<snip code>






When I compile with g++, there is error like:
stack.cpp:18: warning: friend declaration `std::eek:stream&
operator<<(std::eek:stream&, const Stack<T>&)' declares a non-template
function
stack.cpp:18: 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
/tmp/ccrvlcDf.o(.text+0x13f): In function `main':
: undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Stack<char> const&)'
/tmp/ccrvlcDf.o(.text+0x1b8): In function `main':
: undefined reference to `operator<<(std::basic_ostream<char,
std::char_traits<char> >&, Stack<char> const&)'
collect2: ld returned 1 exit status
I think it's totally legal to make a friend function inside a template
class declaration, why there is an error like this?It is, but gcc is kind enough to tell you that your declaration is a
non-template function in the context it is declared (Stack<T> being
whatever instance of the template is being instantiated).

Follow the compiler's advice and all will be well, either

template <class T> class Stack;

template<class T>
ostream& operator<<(ostream& os, const Stack<T>& s)

{
s.msg("Stack contents:");
int t = s.top;
while (t > s.EmptyStack)
cout << s.elements[t--] << endl;
return os;

}Before the class, with

friend ostream& operator<< <>(ostream& os, const Stack<T>& s);

in the class, or simply inline the function in the class declaration.

Note you should be using const char* m (or const std::string& ) as the
parameter for your msg member.
 
G

Gianni Mariani

I have the following code:

.... code snipped.
I think it's totally legal to make a friend function inside a template
class declaration, why there is an error like this?

To overload the << operator on a std::eek:stream, you need to provide the
same signature : i.e.

template<
typename i_char_type,
class i_traits
basic_ostream<i_char_type, i_traits>& operator << (
basic_ostream<i_char_type, i_traits> & i_ostream,
const at::StackFrame & i_value
)...

A friend declaration does not create a declaration in the surrounding
namespace.


This below seems to work .... I have not looked at it for other issues
except for what I think might be a type on the operator<< implementation.

Also, get in the habbit of initializing everything using an initializer
list in your constructors.

#include <iostream>
#include <cstdlib>
#include <cassert>
using namespace std;

template <class T> class Stack;

template<
typename i_char_type,
class i_traits,
class TZ
basic_ostream<i_char_type, i_traits>& operator << (
basic_ostream<i_char_type, i_traits> &,
const Stack<TZ> &
);

template <class T>
class Stack{
public:
enum{DefaultStack = 10, EmptyStack = -1};
Stack();
Stack(int);
~Stack();
void push(const T&);
T pop();
T topNoPop() const;
bool empty() const;
bool full() const;
// friend ostream& operator<<(ostream& os, const Stack<T>& s);
template<
typename i_char_type,
class i_traits,
class TZ
friend basic_ostream<i_char_type, i_traits>& operator << (
basic_ostream<i_char_type, i_traits> &,
const Stack<TZ> &
);
private:
T* elements;
int top;
int size;
void allocate(){
elements = new T[size];
top = EmptyStack;
}
void msg(char m[]) const{
cout << "*** " << m << " ***" << endl;
}


};

template<
typename i_char_type,
class i_traits,
class T
basic_ostream<i_char_type, i_traits>& operator << (
basic_ostream<i_char_type, i_traits> & os,
const Stack<T> & s
)
{
s.msg("Stack contents:");
int t = s.top;
while (t > s.EmptyStack)
os << s.elements[t--] << endl;
// was cout - changed to os
return os;
}

template<class T>
Stack<T>::Stack(){
// *** use initializers to initialize all members
size = DefaultStack;
allocate();
}

template<class T>
Stack<T>::Stack(int s){
// *** use initializers to initialize all members
if (s < 0)
s *= -1;
else if (s == 0)
s = DefaultStack;
size = s;
allocate();
}

template<class T>
Stack<T>::~Stack(){
delete[] elements;
}

template<class T>
void Stack<T>::push(const T& e){
assert(!full());
if (!full())
elements[++top] = e;
else
msg("Stack full!");
}

template<class T>
T Stack<T>::pop(){
assert(!empty());
if (!empty())
return elements[top--];
else{
msg("Stack empty!");
T dummy_value;
return dummy_value; //return arbitrary value
}
}

template<class T>
T Stack<T>::topNoPop() const{
assert(top > EmptyStack);
if (!empty())
return elements[top];
else{
msg("Stack Empty!");
T dummy_value;
return dummy_value;
}
}

template<class T>
bool Stack<T>::empty() const{
return top <= EmptyStack;
}

template<class T>
bool Stack<T>::full() const{
return top + 1 >= size;
}


int main(){

Stack<char> cStack(20);

cout << cStack << endl; //empty stack


cout << "pushing A, B" << endl;
cStack.push('A');
cStack.push('B');
cout << cStack << endl; //BA
return 0;
}
 
I

Ian Collins

(e-mail address removed) wrote:

Please don't top post.
Sorry, I didn't get you. Actually if I write this friend function in
class defintition, it won't have any problem. But why when I define it
out of the class, the compiler complains?
I think Gianni's explanation is better than mine :)

The way I see it is that when the template is instantiated, Stack<T> is
a concrete type, so the friend declaration is effectively declaring

ostream& operator<<(ostream& os, const Stack<char>& s);

as a friend function, which isn't a function template.

If you where to write

template<class X> friend ostream& operator<<(ostream& os, const
Stack<X>& s);

and the function template has been declared in the current scope, the
compiler can match the correct function template.

Remember, just declaring a friend function within a class template
doesn't make that function a template.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top