linker errors when I use template friends?

J

John Harrison

william xuuu said:
Actually, I also got linker errors with template functions and template
classes. And I avoided both of them successfully, by pouring foo.cpp
into foo.h, according to the C++ FAQ.

(http://www.parashift.com/c++-faq-lite/containers-and-templates.html)

And then, I pre-declared each template friend function above the
definition of template class. But I still get template friends linker
error. My compiler is gcc 3.3.3. Any hints? Thanks,

Probably your 'pre-declaration' is not the same as your actual definition.
So the linker tries to find the definiton for you pre-declaration and finds
nothing. Show us the code.

Don't #include foo.cpp in foo.h, that just makes things unnecessarily
complicated. Put everthing into foo.h and throw away foo.cpp. You know it
makes sense.

john
 
W

william xuuu

Actually, I also got linker errors with template functions and template
classes. And I avoided both of them successfully, by pouring foo.cpp
into foo.h, according to the C++ FAQ.

(http://www.parashift.com/c++-faq-lite/containers-and-templates.html)

And then, I pre-declared each template friend function above the
definition of template class. But I still get template friends linker
error. My compiler is gcc 3.3.3. Any hints? Thanks,
 
W

William Xuuu

John Harrison said:
Probably your 'pre-declaration' is not the same as your actual definition.
So the linker tries to find the definiton for you pre-declaration and finds
nothing. Show us the code.

Okay, here it is: (only two files)
//----------------------- "vector_set.h"

//pre declarations.
template <typename T> class Vector_Set;
template <typename T> Vector_Set<T> operator+ (const Vector_Set<T>& s1,
const Vector_Set<T>& s2);

//begin class itself
template <typename T> class Vector_Set
{
friend Vector_Set<T> operator+ (const Vector_Set<T>& s1, const
Vector_Set<T>& s2);
public:
...
};

// friends implementation
template <typename T> Vector_Set<T> operator+ (const Vector_Set<T>& s1,
const Vector_Set<T>& s2)
{
...
}

//----------------------- "vector_set_main.cpp"

typedef Vector_Set<int> Set;

Set a = Set(10), b = Set(10);
for(int i = 0; i < a.size(); i++)
if(i % 2 == 1)
a.add_member(i);
else
b.add_member(i);

// Here causes error!
a + b;



warnings and errors:

g++ -c vector_set_main.cpp
In file included from vector_set_main.cpp:8:
vector_set.h:29: warning: friend declaration `Vector_Set<T> operator+(const
Vector_Set<T>&, const Vector_Set<T>&)' declares a non-template function
g++ -g vector_set_main.o -O2 -lm -o vector_set_main
vector_set_main.o(.text+0x172): In function `main':
: undefined reference to `operator+(Vector_Set<int> const&, Vector_Set<int> const&)'

does this help?
 
J

John Harrison

template said:
{
friend Vector_Set<T> operator+ (const Vector_Set<T>& s1, const
Vector_Set<T>& s2);

This is a non-template function. It declares (as a friend) this function

typedef Vector_Set<int> Set;

Set a = Set(10), b = Set(10);
for(int i = 0; i < a.size(); i++)
if(i % 2 == 1)
a.add_member(i);
else
b.add_member(i);

// Here causes error!
a + b;

Now the compiler thinks there are two functions to choose from, the
non-template (which you declared as a friend)

Vector_Set<int> operator+ (const Vector_Set<int>& s1, const Vector_Set<int>&
s2);

and the template (which you pre-declared)

template <class T>
Vector_Set<T> operator+ (const Vector_Set<T>& s1, const Vector_Set<T>& s2);

Given this choice the compiler always prefers the non-template. But since
you didn't define a non-template you get a link error.

The answer is to tell the compiler that the friend declaration refers to a
template function. You do that by adding '<T>' or '<>' after operator+.

template <typename T> class Vector_Set
{
friend Vector_Set<T> operator+ <>(const Vector_Set<T>& s1, const
Vector_Set<T>& s2);

It's easy to forget that you can have template and non-template versions of
the same function.

john
 
J

John Harrison

The answer is to tell the compiler that the friend declaration refers to a
template function. You do that by adding '<T>' or '<>' after operator+.

Hmm, seems gcc doesn't always handle the <T> form correctly. I would stick
with <>.

john
 
G

Greg Comeau

Okay, here it is: (only two files)
//----------------------- "vector_set.h"

//pre declarations.
template <typename T> class Vector_Set;
template <typename T> Vector_Set<T> operator+ (const Vector_Set<T>& s1,
const Vector_Set<T>& s2);

//begin class itself
template <typename T> class Vector_Set
{
friend Vector_Set<T> operator+ (const Vector_Set<T>& s1, const
Vector_Set<T>& s2);
public:
...
};

// friends implementation
template <typename T> Vector_Set<T> operator+ (const Vector_Set<T>& s1,
const Vector_Set<T>& s2)
{
...
}

//----------------------- "vector_set_main.cpp"

typedef Vector_Set<int> Set;

Set a = Set(10), b = Set(10);
for(int i = 0; i < a.size(); i++)
if(i % 2 == 1)
a.add_member(i);
else
b.add_member(i);

// Here causes error!
a + b;



warnings and errors:

g++ -c vector_set_main.cpp
In file included from vector_set_main.cpp:8:
vector_set.h:29: warning: friend declaration `Vector_Set<T> operator+(const
Vector_Set<T>&, const Vector_Set<T>&)' declares a non-template function
g++ -g vector_set_main.o -O2 -lm -o vector_set_main
vector_set_main.o(.text+0x172): In function `main':
: undefined reference to `operator+(Vector_Set<int> const&, Vector_Set<int> const&)'

does this help?

Like John and your warning say: the decl is not the same
as the definition. Your fried declares a non-template op+ however
your definition is for a template one. Figure out which you
need and use the same for both.
 
W

William Xuuu

Hmm, it works fine by adding <> or <T> as follows.

//begin class itself
template <typename T> class Vector_Set
{

friend Vector_Set<T> operator+<T> (const Vector_Set<T>& s1, const
Vector_Set<T>& s2);
};

While, the C++ FAQ didn't add <> or <T> ?!

Then I find it's not allowed to use + as:

a +<int> b;

So ?
Hmm, seems gcc doesn't always handle the <T> form correctly. I would stick
with <>.

Could you explain the differences between <T> and <> ?

And, i find that either adding <T> after pre-declaration or its
implementation, as:

//pre declarations.
template <typename T> class Vector_Set;
template <typename T> Vector_Set<T> operator+<T> (const Vector_Set<T>& s1,
const Vector_Set<T>& s2);


// friends implementation
template <typename T> Vector_Set<T> operator+<T> (const Vector_Set<T>& s1,
const Vector_Set<T>& s2)
{ ... }


both would cause same error:

error: partial specialization `operator+<T>' of function template

Why would it happen?
 
G

Greg Comeau

Hmm, it works fine by adding <> or <T> as follows.

//begin class itself
template <typename T> class Vector_Set
{

friend Vector_Set<T> operator+<T> (const Vector_Set<T>& s1, const
Vector_Set<T>& s2);
};

While, the C++ FAQ didn't add <> or <T> ?!

Then I find it's not allowed to use + as:

a +<int> b;

So ?

Not sure what you're asking, but perhaps you're looking for
the long-hand version like a.operator+ said:
Could you explain the differences between <T> and <> ?

And, i find that either adding <T> after pre-declaration or its
implementation, as:

//pre declarations.
template <typename T> class Vector_Set;
template <typename T> Vector_Set<T> operator+<T> (const Vector_Set<T>& s1,
const Vector_Set<T>& s2);


// friends implementation
template <typename T> Vector_Set<T> operator+<T> (const Vector_Set<T>& s1,
const Vector_Set<T>& s2)
{ ... }


both would cause same error:

error: partial specialization `operator+<T>' of function template

Why would it happen?

Because a "primary" template declaration should not mention
it's arguments on its name, which the <T> would do above, but
since it's declared above, the friend is using it in your case,
not declaring it as such.
 
W

William Xuuu

Not sure what you're asking, but perhaps you're looking for
the long-hand version like a.operator+<int>(b);

Right, a.operator+<int>(b), when we declare it to be a member of a
class. But here it's declared as a friend function! So don't we have to
specifly <T> as well? i.e, a +<int> b
 
J

John Harrison

William Xuuu said:
Hmm, it works fine by adding <> or <T> as follows.

The following code produces compiler errors on gcc.

#include <iostream>
using namespace std;

template <typename T> class Vector_Set;
template <typename T> Vector_Set<T> operator+ (const Vector_Set<T>& s1,
const Vector_Set<T>& s2);

template <typename T> class Vector_Set
{
friend Vector_Set<T> operator+ <T> (const Vector_Set<T>& s1, const
Vector_Set<T>& s2);
};

template <typename T> Vector_Set<T> operator+ (const Vector_Set<T>& s1,
const Vector_Set<T>& s2)
{
return s1;
}

int main()
{
typedef Vector_Set<int> Set;
Set a, b;
a + b;
}

Change <T> to <> in the friend declaration and it compiles, remove using
namespace std and it compiles. I think its a gcc bug.

john
 
J

John Harrison

Right, a.operator+<int>(b), when we declare it to be a member of a
class. But here it's declared as a friend function! So don't we have to
specifly <T> as well? i.e, a +<int> b

I think you're confused, a.operator+<int>(b) isn't a declaration, its a
function call.

a + b works because in C++ the template function to call is deduced from the
types of the arguments. You can specify the type by appending them after the
function name

func<int>(a, b)

if you want or need to be explicit about template parameters but this syntax
isn't available for the operator form of a function call, which is why Greg
advised

a.operator+<int>(b)

john
 

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,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top