Error compiling templates

Z

ZikO

Hi

I have just type some codes from the book to understand templates. The
code below simply put another method to vector<T> which is sort();

When learning templates in C++, I found something I don't understand.
Please, find below three codes: Sortable.h, Urand.h and main.cpp which
uses those 2 headers.

In part and full template specialization, I don't understand that at
partial specialization (when type is a pointer) I used the syntax
template<class T> class ... {}; etc.
However, at the full specialization this does not work. I had to comment
this part in Sortable.h (it can be seen right before full specialization
of the member function sort()).

If I uncomment this, compiler says:
"main.cpp:59: error: aggregate 'Sortable<char*> scp' has incomplete type
and cannot be defined"

and in the Sortable.h it says:
"..\/Sortable.h:53: error: expected template-name before '<' token
...\/Sortable.h:53: error: expected '{' before '<' token
...\/Sortable.h:53: error: expected unqualified-id before '<' token
...\/Sortable.h:63: error: invalid use of incomplete type 'class
Sortable<char*>'
...\/Sortable.h:17: error: declaration of 'class Sortable<char*>'"

Why I am not to use the same pattern as before, with template<> class
Sortable<char*> : public vector<char*> { // ... }; ?

Does it mean when I have general template and I want to put full
specialization of some methods, I can just specialize just those methods
without template<> class etc.? I am confused here :/




Below, there are 3 codes: Urand.h, Sortable.h and main.cpp

Code:
/*
 * Urand.h
 *
 *  Created on: 2 Sep 2009
 *      Author: User
 */

#ifndef URAND_H_
#define URAND_H_
#include <bitset>
#include <cstddef>
#include <cstdlib>
#include <ctime>
using std::size_t;
using std::bitset;

template<size_t UpperBound>
class Urand {
	bitset<UpperBound> used;
public:
	Urand() {
		srand(time(0)); // losowo
	}
	size_t operator()(); // funkcja generator
};

template<size_t UpperBound>
inline size_t Urand<UpperBound>::operator()() {
	if(used.count() == UpperBound)
		used.reset(); // i od nowa (wyczysc bitset)
	size_t newval;
	while(used[newval = rand() % UpperBound]);
	used[newval] = true;
	return newval;
}

#endif /* URAND_H_ */

Code:
/*
 * Sortable.h
 *
 *  Created on: 2 Sep 2009
 *      Author: User
 */

#ifndef SORTABLE_H_
#define SORTABLE_H_
#include <string>
#include <vector>
#include <cstring>

using std::size_t;

template<class T>
class Sortable : public std::vector<T> {
public:
	void sort();
};

template<class T>
void Sortable<T>::sort() {
	for(size_t i = this->size(); i > 0; --i)
		for(size_t j = 1; j < i; ++j)
			if(this->at(j-1) > this->at(j)) {
				T t = this->at(j-1);
				this->at(j-1) = this->at(j);
				this->at(j) = t;
			}
}

// Specjalizacja czesciowa dla wskaznikow
template<class T>
class Sortable<T*> : public std::vector<T*> {
public:
	void sort();
};

template<class T>
void Sortable<T*>::sort() {
	for(size_t i = this->size(); i > 0; --i)
		for(size_t j = 1; j < i; ++j)
			if(*this->at(j-1) > *this->at(j)) {
				T* t = this->at(j-1);
				this->at(j-1) = this->at(j);
				this->at(j) = t;
			}
}

// Pelna specjalizacja dla char* jako funkcja inline
//template<>
//class Sortable<char*> : public vector<char*> {
//public:
//	void sort();
//};


template<>
void Sortable<char*>::sort() {
	for(size_t i = this->size(); i > 0; --i)
		for(size_t j = 1; j < i; ++j)
			if(std::strcmp(this->at(j-1), this->at(j)) > 0) {
				char* t = this->at(j-1);
				this->at(j-1) = this->at(j);
				this->at(j) = t;
			}
}

#endif /* SORTABLE_H_ */

Code:
/*
 * main.cpp
 *
 *  Created on: 2 Sep 2009
 *      Author: User
 */

#include <cstddef>
#include <iostream>
#include "Sortable.h"
#include "Urand.h"

using namespace std;

#define asz(a) (sizeof a / sizeof a[0])

char* words[] = {
		"is",
		"running",
		"big",
		"dog",
		"a"
};

char* words2[] = {
		"this",
		"that",
		"theother"
};

int main() {
	Sortable<int> is;
	Urand<47> rnd;
	for(size_t i = 0; i < 15; ++i)
		is.push_back(rnd());
	for(size_t i = 0; i < is.size(); ++i)
		cout << is[i] << " ";
	cout << endl;
	is.sort();
	for(size_t i = 0; i < is.size(); ++i)
		cout << is[i] << " ";
	cout << endl;

	// wykorzystywana czesciowa specjalizacja
	Sortable<string*> ss;
	for(size_t i = 0; i < asz(words); ++i)
		ss.push_back(new string(words[i]));
	for(size_t i = 0; i < ss.size(); ++i)
		cout << *ss[i] << " ";
	cout << endl;
	ss.sort();
	for(size_t i = 0; i < ss.size(); ++i) {
		cout << *ss[i] << " ";
		delete ss[i];
	}
	cout << endl;

	// Wykorzystywana calkowita specjalizacja
	Sortable<char*> scp;
	for(size_t i = 0; i < asz(words2); ++i)
		scp.push_back(words2[i]);
	for(size_t i = 0; i < scp.size(); ++i)
		cout << scp[i] << " ";
	cout << endl;
	scp.sort();
	for(size_t i = 0; i < scp.size(); ++i) {
		cout << scp[i] << " ";
	}
}
 
F

Francesco

If I uncomment this, compiler says:
"main.cpp:59: error: aggregate 'Sortable<char*> scp' has incomplete type
and cannot be defined"

Hi ZikO,
you forgot the std:: qualifier before "vector".

Take advantage of http://www.comeaucomputing.com/tryitout/ (I used it
to spot your error)

Have good coding,
Francesco

PS: take the habit to write your comments in English, comments can be
useful to the people revising your code - if they can understand
them :)
 
F

Francesco

Why I am not to use the same pattern as before, with template<> class
Sortable<char*> : public vector<char*> { // ... }; ?

Does it mean when I have general template and I want to put full
specialization of some methods, I can just specialize just those methods
without template<> class etc.? I am confused here :/

Commenting out the part that didn't work you specialized only
Sortable<T*>::sort() for char*.

Since you can create a Sortable<char*> class instance via the
Sortable<T*> class template, you aren't requested to create a specific
Sortable<char*> specialization.

But if you implement the above specialization, then you have to modify
Sortable<char*>::sort() - you must remove "template<>" before of it,
otherwise the compiler complains that your specialization doesn't
match any template declaration - although I'm not so sure about the
reason.

In any case, by removing "template<>" you are telling that it is not a
specialization of another template template function - as you did
before - but, instead, that it is the definition of the function that
you declared into the Sortable<char*> template class.

When using templates, many things can be specialized or not. Actually,
some specializations aren't really required, but can come useful, for
instance, to improve performance on a specific type.

Hope this helped to clear out your confusion.

Best regards,
Francesco
 
Z

ZikO

Hi ZikO,
you forgot the std:: qualifier before "vector".

Take advantage of http://www.comeaucomputing.com/tryitout/ (I used it
to spot your error)

Have good coding,
Francesco

PS: take the habit to write your comments in English, comments can be
useful to the people revising your code - if they can understand
them :)

Thanks Francesco


There was certainly problem with lack of qualifier std:: but there's
also problem with template itself. I cannot understand why in full
special. I must comment these lines which are already commented.

Probably things must be this way.

Regards.

PS. I will keep it in my mind to make comments in English =)
 
F

Francesco

Thanks Francesco

You're welcome.
There was certainly problem with lack of qualifier std:: but there's
also problem with template itself. I cannot understand why in full
special. I must comment these lines which are already commented.

Probably things must be this way.

No, not really. I forgot a thing and I posted another message, have a
look up-thread.
PS. I will keep it in my mind to make comments in English =)

Good habit to take on ;-)

Cheers,
Francesco
 
Z

ZikO

Commenting out the part that didn't work you specialized only
Sortable<T*>::sort() for char*.

Since you can create a Sortable<char*> class instance via the
Sortable<T*> class template, you aren't requested to create a specific
Sortable<char*> specialization.

But if you implement the above specialization, then you have to modify
Sortable<char*>::sort() - you must remove "template<>" before of it,
otherwise the compiler complains that your specialization doesn't
match any template declaration - although I'm not so sure about the
reason.

This is why I am confused here. From what I have read, we are generally
In any case, by removing "template<>" you are telling that it is not a
specialization of another template template function - as you did
before - but, instead, that it is the definition of the function that
you declared into the Sortable<char*> template class.

It seems like using specialization for specific type is actually
defining regular function. I will try to remember that =)
When using templates, many things can be specialized or not. Actually,
some specializations aren't really required, but can come useful, for
instance, to improve performance on a specific type.

Hope this helped to clear out your confusion.

It's certainly clearer at the moment, although I really need more
practice in that area :p

Thanks Francesco.
 
F

Francesco

This is why I am confused here. From what I have read, we are generally


It seems like using specialization for specific type is actually
defining regular function. I will try to remember that =)

Thinking again is seems logic. After all, as I said, that's just a
definition of an already declared, "not specifically a template"
method. On the other hand, the "mandated" syntax seems to be different
for template classes and template methods.

For and odd example, you might try this:
-------
template<>
class Sortable<char*> : public std::vector<char*> {
public:
template<class T>
std::vector<T> convert(size_t item);

//if you omit the following, the compiler complains below
std::vector<int> convert(size_t item);
};

template<class T>
std::vector<T>
Sortable<char*>::convert(size_t item) {
std::vector<T> result;
if(item < size()) {
char* ptr = operator[](item);
while(*ptr) {
result.push_back(T(*ptr++));
}
}
return result;
}

//template<> // <--- necessary only if not declared in the class
std::vector<int>
Sortable<char*>::convert(size_t item) {
std::vector<int> result;
if(item < size()) {
char* ptr = operator[](item);
while(*ptr) {
result.push_back(int(*ptr++));
}
}
return result;
}
-------

In the case above, the commented out "template<>" line is _necessary_
only if the "int" specialization of the "convert" method is _not_
declared into the class.

If you declare it and you uncomment the above "template<>" line, then
the compiler won't complain, it won't make any difference about
"template<>" being present or not.

Seems like this works differently for class templates and for method
templates... well, whatever makes the compiler's day ;-)
It's certainly clearer at the moment, although I really need more
practice in that area :p

Thanks Francesco.

You're welcome. Well, I need more practice too, you're not alone :)

Cheers,
Francesco
 
F

Francesco

This is why I am confused here. From what I have read, we are generally
requested to use "template<>" to tell compiler about using full
specialization.
It seems like using specialization for specific type is actually
defining regular function. I will try to remember that =)

Thinking again is seems logic. After all, as I said, that's just a
definition of an already declared, "not specifically a template"
method. On the other hand, the "mandated" syntax seems to be different
for template classes and template methods.

For and odd example, you might try this:
-------
template<>
class Sortable<char*> : public std::vector<char*> {
public:
template<class T>
std::vector<T> convert(size_t item);

//if you omit the following, the compiler complains below
std::vector<int> convert(size_t item);

};

template<class T>
std::vector<T>
Sortable<char*>::convert(size_t item) {
std::vector<T> result;
if(item < size()) {
char* ptr = operator[](item);
while(*ptr) {
result.push_back(T(*ptr++));
}
}
return result;

}

//template<> // <--- necessary only if not declared in the class
std::vector<int>
Sortable<char*>::convert(size_t item) {
std::vector<int> result;
if(item < size()) {
char* ptr = operator[](item);
while(*ptr) {
result.push_back(int(*ptr++));
}
}
return result;}

-------

In the case above, the commented out "template<>" line is _necessary_
only if the "int" specialization of the "convert" method is _not_
declared into the class.

If you declare it and you uncomment the above "template<>" line, then
the compiler won't complain, it won't make any difference about
"template<>" being present or not.

Seems like this works differently for class templates and for method
templates... well, whatever makes the compiler's day ;-)

All right, I understood this point about my example built on your
code, ZikO. If I specify "template<>" I'm specializing the template
function, otherwise I'm defining the overloaded function declared into
the class. This will lead to an undefined reference, if the "convert"
function is called without the "<type>" specification.

But now I stomped again on something strange - strange for me :-/

Consider this code:
-------
#include <iostream>

using namespace std;

template<class T> struct A {
T data;
};

template<> // necessary, classes and structs
// cannot be overloaded
struct A<int> {
int data;
};

struct B {
template<class T> T func(T data);
int func(int data); // overloading
};

template<class T> T B::func(T data) {
return data * 2;
}

// specialization
template<>
int B::func(int data) {
return data;
}

// definition of the overloaded function
int B::func(int data) {
return -data;
}

int main()
{
B b;
double d = 2.2;
int i = 10;

// uses the generic template function
cout << b.func(d) << endl;

// explicit call to the specialization
cout << b.func<int>(i) << endl;

// resolves to the overloaded function
// but souldn't this be ambiguous, since
// I defined the above specialization?
cout << b.func(i) << endl;

return 0;
}
-------

The above produces this output:

-------
4.4
10
-10
-------

I wonder if there is a clause that imposes the above behavior, or if
some other compiler could resolve the call to the specialized template
function instead.

Somebody else is following this thread and can drop in for a
clarification?
That would be really appreciated.

Cheers,
Francesco
 

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

Similar Threads

templates?? 2
templates 10
Templates and g++ 4
Crossword 2
Variadic templates std::tuple 2
variadic templates - compile error 4
Fibonacci 0
Filter sober in c++ don't pass test 0

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top