How can I declare and define a friend template function in a template class?

  • Thread starter =?gb2312?B?wfXquw==?=
  • Start date
?

=?gb2312?B?wfXquw==?=

Hi folks,
I am running into with such a question when I tried to declare and
define a friend template function in a template class, here is the
code snippet:

#include <iostream>
using namespace std;

template<typename T>
class Test {

friend Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step);
};

template<typename T>
Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step) {
cout << "This is index is working\n";
return Test<T>();
}


int main() {

Test<int> start = Test<int>();
Test<int> end = Test<int>();
Test<int> step = Test<int>();

Test<int> rslt = index(start, end, step);
}

When compiled with VC8.0, a linkage error araised:

Test.obj : error LNK2019: unresolved external symbol "class TVEC<int>
__cdecl index(class TVEC<int> &,class TVEC<int> &,class TVEC<int>
&)" (?index@@YA?AV?$TVEC@H@@AAV1@00@Z) referenced in function _main
 
V

Victor Bazarov

Áõê» said:
Hi folks,
I am running into with such a question when I tried to declare and
define a friend template function in a template class, here is the
code snippet:

#include <iostream>
using namespace std;

template<typename T>
class Test {

friend Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step);

Since 'index' is a template, it has to be declared at the namespace level
before it's declared here. Otherwise, this friend declaration refers to
a non-template function.

Take the declaration of 'index' from below (not the whole definition)
and place it before the template definition. That will require the
template itself to be *declared* before it, as well. I know, I know,
it's a PITA, but that's what is required.
};

template<typename T>
Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step) {
cout << "This is index is working\n";
return Test<T>();
}


int main() {

Test<int> start = Test<int>();
Test<int> end = Test<int>();
Test<int> step = Test<int>();

Test<int> rslt = index(start, end, step);
}

When compiled with VC8.0, a linkage error araised:

Test.obj : error LNK2019: unresolved external symbol "class TVEC<int>
__cdecl index(class TVEC<int> &,class TVEC<int> &,class TVEC<int>
&)" (?index@@YA?AV?$TVEC@H@@AAV1@00@Z) referenced in function _main

This is what your code should look like (I think):

#include <iostream>
using namespace std;

template<typename T> class Test;

template<typename T>
Test<T> index(Test<T>& start, Test<T>& end, Test<T>& step);

template<typename T>
class Test {
... // as before


V
 
?

=?gb2312?B?wfXquw==?=

First, thank you for your informative tips, I rewrite my code snippet,
here it is:

#include <iostream>
using namespace std;

template<typename T>
class Test;

template<typename T>
Test<T> index(T start, T end, T step);

template<typename T>
class Test {
public:
friend Test<T> index(T start, T end, T step);
};

template<typename T>
Test<T> index(T start, T end, T step) {
cout << "This is index is working\n";
return Test<T>();
}

int main() {

int start;
int end;
int step;

index(start, end, step);
}

It's the same as you think it is supposed to be, no problem with
compling and linking, but at runtime, a error is raised.
 
V

Victor Bazarov

Áõê» said:
First, thank you for your informative tips, I rewrite my code snippet,
here it is:

#include <iostream>
using namespace std;

template<typename T>
class Test;

template<typename T>
Test<T> index(T start, T end, T step);

template<typename T>
class Test {
public:
friend Test<T> index(T start, T end, T step);
};

template<typename T>
Test<T> index(T start, T end, T step) {
cout << "This is index is working\n";
return Test<T>();
}

int main() {

int start;
int end;
int step;

index(start, end, step);
}

It's the same as you think it is supposed to be, no problem with
compling and linking, but at runtime, a error is raised.

What error do *you* get?

You're passing 'start', 'end', 'step' into the function _without_
_giving them any value_. The lvalue-to-rvalue conversion required
for argument passing causes the program to have *undefined behaviour*.

Try initialising all your variables. Or just call

index(1, 2, 3);

V
 
?

=?gb2312?B?wfXquw==?=

Forget about the runtime error, it's because I used 3 variables before
I define them, sorry about that, it's OK when I initialize them. But a
new linkage error show itself when I tried to assign the return value
of index to another Test<T> object, here is the code snippet:

#include <iostream>
using namespace std;

template<typename T>
class Test;

template<typename T>
Test<T> index(T start, T end, T step) {
cout << "This is index is working\n";
return Test<T>();
}

template<typename T>
class Test {
public:
friend Test<T> index(T start, T end, T step);

};


int main() {

int start = 1;
int end = 32;
int step = 1;

Test<int> rslt = index(start, end, step);
}

The error is:

Test.obj : error LNK2019: unresolved external symbol "class Test<int>
__cdecl index(int,int,int)" (?index@@YA?AV?$Test@H@@HHH@Z) referenced
in function _main
 
H

hurcan solter

should be;


template<typename T>
class Test {
public:
template<typename T> //look here
friend Test<T> index(T start, T end, T step);

};
 
V

Victor Bazarov

hurcan said:
should be;


template<typename T>
class Test {
public:
template<typename T> //look here
friend Test<T> index(T start, T end, T step);

};

You can't redefine 'T' here, I think. If you only wanted to make
the 'index<T>' a friend (instantiated on the same 'T' as the class
'Test'), then a pair of angle brackets is in order (I missed that
in my post:

template<typename T>
class Test {
public:
friend Test<T> index<>(T start, T end, T step);
// ^^^^
};

V
 
H

hurcan solter

You can't redefine 'T' here, I think. If you only wanted to make
the 'index<T>' a friend (instantiated on the same 'T' as the class
'Test'), then a pair of angle brackets is in order (I missed that
in my post:

template<typename T>
class Test {
public:
friend Test<T> index<>(T start, T end, T step);
// ^^^^
};
yes you can. it's so called friend template, in that case,all
instantiantions of the
template is the friend of class Test.Not that it's useful in this case
though, so yours
is the probably way to go.
 
V

Victor Bazarov

hurcan said:
yes you can. it's so called friend template, in that case,all
instantiantions of the
template is the friend of class Test.Not that it's useful in this case
though, so yours
is the probably way to go.

I repeat, the name 'T' shall not be redeclared in the definition of
'Test' for any other purpose. Try this:

template<class T> class A {
A(T) {}
template<class T> friend void foo(T t);
// template<class U> friend void foo(U u);
};

template<class T> void foo(T t)
{
A<A<T> > aat(A<int>(42));
}

int main()
{
foo(0);
}

Then, after it fails, comment the 'foo(T t)' declaration in the
class template, and uncomment the 'foo(U u)' declaration and try
again.

V
 
G

Guest

Hi folks,

Thanks for your informative tips, both of your answers can solve my
problem successfully. But I have a question coming into my mind:

If there is any difference between:

template<typename T>
class Test {
friend Test<T> index<>(T, T, T);
// ^^^
};

and

class Test {
friend Test<T> index<T>(T, T, T);
// ^^^
};

I know you've explained it, but how can I prove that they are indeed
different, thank you.
 
V

Victor Bazarov

Thanks for your informative tips, both of your answers can solve my
problem successfully. But I have a question coming into my mind:

If there is any difference between:

template<typename T>
class Test {
friend Test<T> index<>(T, T, T);
// ^^^
};

and

class Test {
friend Test<T> index<T>(T, T, T);
// ^^^
};

I know you've explained it, but how can I prove that they are indeed
different, thank you.

I am not sure they are different, to be honest. The <T> after 'index'
is actually implied by the empty angle brackets.

Now, if you were to write

template<class T>
class Test {
template<class U> friend Test<U> index(U,U,U);
};

That would definitely be different. It means that _any_ instantiation
of the 'index' template is a friend of this instantiation of 'Test'.
The usefulness of that is questionable, but it would allow you to do

template<class S> Test<S> index(S s1, S s2, S s3)
{
Test<blalblah> someOtherTest;
// and then access 'someOtherTest's privates
}

V
 

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

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top