Sign in to follow this  
jhq

friend function & template

Recommended Posts

I write some codes like this:
template<class T>
class test
{

	vector<int> v;
public:
	test()
		:v(10, 1)
	{}

	friend void show_test(test<T>&);
};

template<class T>
void show_test(test<T>& t)//friend function of test
{
	for(unsigned short i = 0; i < t.v.size(); ++i)
		cout << t.v[i] << " ";
	cout << endl;
}

void demo_test()
{
	test<int> t;
	
	show_test(t);
}

int main()
{
	demo_test();

	return 0;
}

But the compiler always pops: Linking... cpptest.obj : error LNK2001: unresolved external symbol "void __cdecl show_test(class test<int> &)" (?show_test@@YAXAAV?$test@H@@@Z) what's wrong here?

Share this post


Link to post
Share on other sites
You need to tell the compiler that the friend function is a template in the declaration. You can do this by appending empty <> brackets to the name like this:
friend void show_test<>(test<T>&);

Share this post


Link to post
Share on other sites
The problem lies in that friend templates require explicit statement of the fact they are templates. Hence the following (with some additional comments :) )



// Don't forget to include headers so we can reproduce the example!
#include <vector>
#include <iostream>

using namespace std; // Bleh


template<class T>
class test
{
vector<int> v;
public:
test() : v(10,1) {}
// Note the additional syntax making the template statement explicit
template <typename T> friend void show_test(test<T>&);
};


// Firstly this function shouldn't be a free function; it should be a "Report" member function of test
template<class T>
void show_test(test<T>& t)
{
// Firstly tidying up the loop the way you wrote it
// How do you know "i" is an unsigned short?
for(unsigned short i = 0; i < t.v.size(); ++i)

// We are assuming v will be a vector<int>, what if you change the test class and forget to change this?
// Take advantage of the nested typedefs
// Note that this is a good illustration of why friendship is the strongest relationship classes can have to each other:
// for(vector<int>::size_type i = 0; i < t.v.size(); ++i)

cout << t.v[i] << " ";
cout << endl;

// And this is how I would do it, which makes life a lot easier!
// However, we are still using the int template variable explicitly - friendship, bleh
copy(t.v.begin(), t.v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}


int main()
{
test<int> t;
show_test(t);
// So sue me, I used system("pause")
system("pause");
return 0;
}


// The class we could have had!
// I am assuming here that the container should have been of T and not int; otherwise why template?
template<class T>
class test2
{
vector<T> v;
public:
test2() : v(10,1) {}

void Report()
{
copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
cout << endl;
}
};




Share this post


Link to post
Share on other sites
Hollower, I am afraid that you suggestion doesn't work. Maybe it's compiler issue(My compiler is vc2005). Anyway, thanks a lot!

Also, special thanks to you, JimPrice! Especially your additional comments. Now everything is done. :)

Share this post


Link to post
Share on other sites
Quote:
I also found another solution which uses the template <class ...> variant here


The two 'solutions' are identicle. In the context of a template class and typename both mean the same thing, that the template paramater is a type :). (exception: template template paramaters)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this