Sign in to follow this  
Zmurf

Templates, Classes, Structs Problems

Recommended Posts

Zmurf    100
I'm having problems using templates with classes and structs.
template <class T> class MyClass
{
public:
template <class U> struct MyStruct
{
val1;
val2;
};

vector <T> m_Vector;

void addtovector(T v1, T v2);
};

MyClass<class T>::addtovector(T v1, T v2){
MyStruct<T> temp = {v1, v2};
m_Vector.push_back(temp)
}
How can I get something like this to work?

Share this post


Link to post
Share on other sites
Eddycharly    437

template <class T> class MyClass
{
public:

template <class U> struct MyStruct
{
U val1;
U val2;
};

vector <MyStruct <T> > m_Vector;

void addtovector(T v1, T v2)
{
MyStruct<T> temp = {v1, v2};
m_Vector.push_back(temp)
}
};


Share this post


Link to post
Share on other sites
Enigma    1410
Quote:
Original post by Eddycharly
Also, you should change the 'class' template parameter type to 'typename', so that it works with simple types like ints, floats, etc...

Quote:
C++ Standard, Final Draft, Section 14.1, Paragraph 1
There is no semantic difference between class and typename in a template-parameter.

Enigma

Share this post


Link to post
Share on other sites
snk_kid    1312

#include <utility> // std::pair
#include <vector>

template < typename Tp >
struct foo {

typedef std::pair<Tp, Tp> identical_pair;
typedef std::vector<identical_pair> vec_type;

private:

vec_type m_Vector;

public:

void addtovector(const Tp& v1, const Tp& v2) {
m_Vector.push_back(identical_pair(v1, v2));
}
};

Share this post


Link to post
Share on other sites
MaulingMonkey    1730
Quote:
Original post by Zmurf
Still getting errors.

error C2079: 'MyClass<T>::MyStruct<U>::val1' uses undefined class 'T'


...

Eddycharly allready got it. Adding the include and "using namespace std;", as well as adding a semicolon after the push_back, and it compiles.

#include <vector>
using namespace std;

template <class T> class MyClass
{
public:

template <class U> struct MyStruct
{
U val1;
U val2;
};

vector <MyStruct <T> > m_Vector;

void addtovector(T v1, T v2)
{
MyStruct<T> temp = {v1, v2};
m_Vector.push_back(temp);
}
};





It works. Of course, if you're still having problems, things that could really help are:

1) Whatever you're actually trying to compile, not something obviously wrong in twenty bazillion manners (missing types, includes, using declerations, ...) nor the code that, compiling fine, you obviously arn't using.

2) Not psuedo-typed out, %#^*(&ing copy and pasted. CTRL+C and CTRL+V. That way I feel less like I'm trying to navigate paris with a new york subway map. I get a copy and can see everything from the typeo in line 2347589235 of module 13, to the fact that you're trying to call eat( steel_rebarb & ). It's customary to try to simplify the problem to see what exactly is triggering it of course, but it's not going to help if you inadvertantly eliminated all traces of the problem. The way to prevent this is to actually try compiling the simplification to make sure it still illustrates the problem.

3) The line the actual error occurs on. This is given to you by your compiler for a reason: to point out where the problem is occuring. Also, all errors - many often occur as a chain reaction of one mistake, and it's not terribly uncommon for them to cause problems twenty bazillion lines away.

Share this post


Link to post
Share on other sites
Eddycharly    437
Quote:

C++ Standard, Final Draft, Section 14.1, Paragraph 1
There is no semantic difference between class and typename in a template-parameter.


That's strange, i wonder why we have two keywords for the same thing then...
Annyway, thanks for pointing it out.

Share this post


Link to post
Share on other sites
stylin    758
Quote:
Original post by Eddycharly
Quote:

C++ Standard, Final Draft, Section 14.1, Paragraph 1
There is no semantic difference between class and typename in a template-parameter.


That's strange, i wonder why we have two keywords for the same thing then...
Annyway, thanks for pointing it out.

For historical reasons, mostly. typename is a relatively recent addition to the language. Note that when introducing template template parameters, class is the only valid qualifier.

Share this post


Link to post
Share on other sites
Zmurf    100
alright heres my exact code in my header file. It was working fine until I wanted to expand it by making it a template class so it can be more versitile.

// Priority List Definition
#ifndef H_PRIORITY_LIST
#define H_PRIORITY_LIST

// Includes
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <math.h>
#include <vector>
#include <string>
#include <iterator>
#include <sstream>
#include <algorithm>

// Namespaces
using namespace std;

template <class T> class plist
{
// Public Members.
public:
plist(); // Constructor, returns nothing.
virtual ~plist(); // Deconstructor, returns nothing.

void add(T val, int pri = 0); // Add a single string.
void addline(string val, bool newOnly = false); // Add a string with multiple words.
void remove(int pos){m_List.erase(m_List.begin() + pos);} // Remove string at position pos.
void sort(); // Sorts the list.
void setpri(int pos, int pri){m_List.at(pos).pri = pri;} // Sets the priority of position pos in the list.

T getf(){return m_List[0].val;} // Returns the first string.
T getb(){return m_List[m_List.size()].val;} // Returns the last string.
T get(int pos){return m_List.at(pos).val;} // Returns the string at position pos.

int size(){return m_List.size();} // Returns the size of the list.
int find(string val); // Finds the first instance of str in the list and
// returns its position.

// Private Members.
private:
// Structure to hold the list data in a single vector.
template <class U> struct m_ListDec
{
U val;
int pri;

bool operator<(const m_ListDec &rhs) const {
return pri < rhs.pri;
}
bool operator>(const m_ListDec &rhs) const {
return pri > rhs.pri;
}
};

vector< m_ListDec<T> > m_List;

// Protected Members.
protected:
};

#endif

void plist<class T>::add(T val, int pri){
m_ListDec<T> temp = {val, pri};
m_List.push_back(temp);
}

void plist<class T>::addline(string val, bool newOnly){
vector<string> words;

// Split the input string into a vector
istringstream sentance(val);
copy(istream_iterator<string>(sentance), istream_iterator<string>(), back_inserter(words));


// Add the new words to the list.
for(int i = 0; i < (int)(words.size()); ++i){
if (newOnly){
if (find(words.at(i)) != -1)
add(words.at(i), (int)(words.at(i)[0]));
}
else
add(words.at(i), (int)(words.at(i)[0]));
}
}

void plist<class T>::sort(){
std::sort(m_List.begin(), m_List.end());
}

int plist<class T>::find(string val){
for (int i = 0; i < (int)(m_List.size()); ++i){
if (m_List[i].val = val)
return i;
}

return -1;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Ok, I have problems with posting code here because of html tags, but I was told a way to get around this. Hopefully I'll do this right the first time.


template < class T > class MyClass
{
public:
template < class U > struct MyStruct
{
U val1;
U val2;
};

std::vector < MyStruct < T > > m_Vector;

void addtovector(T v1, T v2);
};

template < class T >
void MyClass < T >::addtovector(T v1, T v2)
{
MyStruct < T > temp = {v1, v2};
m_Vector.push_back(temp);
}

I basically just tried to correct your syntax. I hope this helps.

Share this post


Link to post
Share on other sites
MaulingMonkey    1730
Much better :-).

Problem #1: You've got the external member function syntax wrong when it's a member of a template class. It should be:

template < typename T >
return_type class_name< T >::function_name( ... )


Instead of:

return_type class_name< class T >::function_name( ... )


This affects the declerations:

void plist<class T>::add(T val, int pri){
...
}

void plist<class T>::addline(string val, bool newOnly){
...
}

void plist<class T>::sort(){
...
}

int plist<class T>::find(string val){
...
}


Fixing these by switching them to:

template < typename T >
void plist<T>::add(T val, int pri){
...
}

template < typename T >
void plist<T>::addline(string val, bool newOnly){
...
}

template < typename T >
void plist<T>::sort(){
...
}

template < typename T >
int plist<T>::find(string val){
...
}


Allows my compiler to compile that snippet of code just fine. Full redone source bellow:

// Priority List Definition
#ifndef H_PRIORITY_LIST
#define H_PRIORITY_LIST

// Includes
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <math.h>
#include <vector>
#include <string>
#include <iterator>
#include <sstream>
#include <algorithm>

// Namespaces
using namespace std;

template <class T> class plist
{
// Public Members.
public:
plist(); // Constructor, returns nothing.
virtual ~plist(); // Deconstructor, returns nothing.

void add(T val, int pri = 0); // Add a single string.
void addline(string val, bool newOnly = false); // Add a string with multiple words.
void remove(int pos){m_List.erase(m_List.begin() + pos);} // Remove string at position pos.
void sort(); // Sorts the list.
void setpri(int pos, int pri){m_List.at(pos).pri = pri;} // Sets the priority of position pos in the list.

T getf(){return m_List[0].val;} // Returns the first string.
T getb(){return m_List[m_List.size()].val;} // Returns the last string.
T get(int pos){return m_List.at(pos).val;} // Returns the string at position pos.

int size(){return m_List.size();} // Returns the size of the list.
int find(string val); // Finds the first instance of str in the list and
// returns its position.

// Private Members.
private:
// Structure to hold the list data in a single vector.
template <class U> struct m_ListDec
{
U val;
int pri;

bool operator<(const m_ListDec &rhs) const {
return pri < rhs.pri;
}
bool operator>(const m_ListDec &rhs) const {
return pri > rhs.pri;
}
};

vector< m_ListDec<T> > m_List;

// Protected Members.
protected:
};

#endif

template < typename T >
void plist<T>::add(T val, int pri){
m_ListDec<T> temp = {val, pri};
m_List.push_back(temp);
}

template < typename T >
void plist<T>::addline(string val, bool newOnly){
vector<string> words;

// Split the input string into a vector
istringstream sentance(val);
copy(istream_iterator<string>(sentance), istream_iterator<string>(), back_inserter(words));


// Add the new words to the list.
for(int i = 0; i < (int)(words.size()); ++i){
if (newOnly){
if (find(words.at(i)) != -1)
add(words.at(i), (int)(words.at(i)[0]));
}
else
add(words.at(i), (int)(words.at(i)[0]));
}
}

template < typename T >
void plist<T>::sort(){
std::sort(m_List.begin(), m_List.end());
}

template < typename T >
int plist<T>::find(string val){
for (int i = 0; i < (int)(m_List.size()); ++i){
if (m_List[i].val = val)
return i;
}

return -1;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
I guess I should get another post in before this hurricane takes out the power.


// this is incorrect

MyClass< class T>::addtovector(T v1, T v2)
{
//...........
}

// this is correct

template< class T>
void MyClass< T>::addtovector(T v1, T v2)
{
//............
}

If you define a member function outside your class declaration you need to have template< class T> at the begining of each function. Also it should be MyClass< T>:: not MyClass< class T>:: . I believe this is why you recieved the error you posted earlier.

Share this post


Link to post
Share on other sites
Zmurf    100
Thats gets rid of the main errors. Now theres just one left.

It has to do with this line.

template <typename T> 
int plist<T>::find(string val){
for (int i = 0; i < (int)(m_List.size()); ++i){
if (!m_List[i].val.compare(val)) // This line is causing problems.
return i;
}

return -1;
}


And I'm recieving these errors.

Quote:

ChatBot.obj : error LNK2019: unresolved external symbol "public: __thiscall plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)" (??0?$plist@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAE@XZ) referenced in function _$E1


Quote:

ChatBot.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::~plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)" (??1?$plist@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@UAE@XZ) referenced in function _$E11

Share this post


Link to post
Share on other sites
MaulingMonkey    1730
ChatBot.obj : error LNK2019: unresolved external symbol "public: __thiscall plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)" (??0?$plist@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@QAE@XZ) referenced in function _$E1

ChatBot.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >::~plist<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >(void)" (??1?$plist@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@@UAE@XZ) referenced in function _$E11

BoldedColored red the important bits.

"unresolved external symbol" means it couldn't find the actual implementation of something. This is usually either because you frogot to link a library (which implements that function), or because you frogot to implement that function yourself.

If you skim over the huge expanded template parameter list, you can see you frogot to implement the the default constructor (plist::plist( void )) and the deconstructor (plist::~plist( void )).

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