underfined inline function.

S

sam

Hi,

I can't figure out what is the problem of the following coding.
#ifndef __PARSER__
#define __PARSER__

#include <iostream>
#include <string>
#include <fstream>
//#include <exception>
#include <iomanip> // Header for I/O stream manipulators
#include <ext/hash_map>
#include <vector>
#include <list>

#define LLEN 256

// Namespace alias to reach hash_map classes
namespace stdext = ::__gnu_cxx;
using namespace std;
using namespace stdext;

/* struct or */
class HashString
{
public:
/*long*/ int operator()(std::string const &str) const
{
return stdext::hash<char const *>()(str.c_str());
}
};

// This class' function operator() tests if any two keys are equal.

/* struct or */
class HashStringCompare
{
public:
bool operator()(std::string s1, std::string s2) const
{
return s1 == s2;
}
};

class HashMap: public hash_map<string, string, HashString,
HashStringCompare>
{
public:
HashMap(): hash_map<string, string, HashString, HashStringCompare>() {}
};

#define SPACES " \t\n\r" // default "spaces" for trimming strings

class Parser
{
public:
Parser(string &cmd);
Parser(ifstream &f);
virtual int parse() {return 1;};
void _debug(list<HashMap> &l);

// trim spaces from right (you can define what spaces are)
string trim_right (const string & s, const string & t = SPACES);
// trim spaces from left
string trim_left (const string & s, const string & t = SPACES);
// trim spaces from both sides
string trim (const string & s, const string & t = SPACES);

virtual ~Parser() {};

protected:
vector<string> v_data;
};

inline string trim_right (const string & s, const string & t)
{
string d (s);
string::size_type i (d.find_last_not_of (t));
if (i == string::npos)
return "";
else
return d.erase (d.find_last_not_of (t) + 1) ;
} // end of trim_right

inline string trim_left (const string & s, const string & t)
{
string d (s);
return d.erase (0, s.find_first_not_of (t)) ;
} // end of trim_left

inline string trim (const string & s, const string & t)
{
string d (s);
return trim_left (trim_right (d, t), t) ;
} // end of trim

inline Parser::parser(string &cmd)
{
const char *s = cmd.c_str();
string str = trim(s);
if (str.c_str()[0] == '#' || str.length() == 0)
cout << "this is comment: " << str << endl;
else
v_data.push_back(str);
}

int main()
{
string s = " test string ";
Parser p(s);
}

#endif


When compiled with g++ in FreeBSD 5.4, it generated error shown as follow:
# g++ p_test.cpp
/var/tmp//ccJnnMuA.o(.gnu.linkonce.t._ZN6ParserC1ERSs+0xd8): In function
`Parser::parser(std::string&)':
: undefined reference to `Parser::trim(std::string const&, std::string
const&)'
 
G

Gianni Mariani

sam wrote:
....
class Parser
{
public:
Parser(string &cmd);
Parser(ifstream &f);
virtual int parse() {return 1;};
void _debug(list<HashMap> &l);

// trim spaces from right (you can define what spaces are)
string trim_right (const string & s, const string & t = SPACES);
// trim spaces from left
string trim_left (const string & s, const string & t = SPACES);
// trim spaces from both sides
string trim (const string & s, const string & t = SPACES);
This is defined as a regular member function.
virtual ~Parser() {};

protected:
vector<string> v_data;
}; ....

inline string trim (const string & s, const string & t)
This is defined as a global function.
{
string d (s);
return trim_left (trim_right (d, t), t) ;
} // end of trim

Did you mean:

inline string Parser::trim (const string & s, const string & t)

?

Since these functions do not access the object in any way, you can
declare them static member functions. (and probably should).
inline Parser::parser(string &cmd)
{
const char *s = cmd.c_str();
string str = trim(s);
This accesses the member function.
if (str.c_str()[0] == '#' || str.length() == 0)
cout << "this is comment: " << str << endl;
else
v_data.push_back(str);
}

int main()
{
string s = " test string ";
Parser p(s);
}

#endif


When compiled with g++ in FreeBSD 5.4, it generated error shown as follow:
# g++ p_test.cpp
/var/tmp//ccJnnMuA.o(.gnu.linkonce.t._ZN6ParserC1ERSs+0xd8): In function
`Parser::parser(std::string&)':
: undefined reference to `Parser::trim(std::string const&, std::string
const&)'

Not the linker is looking for Parser::trim. You have defined ::trim.
 
T

Thierry Miceli

class Parser
{ .....
// trim spaces from both sides
string trim (const string & s, const string & t = SPACES); .....
};
trim is declarated as a member function of Parser
inline string trim (const string & s, const string & t)
{
string d (s);
return trim_left (trim_right (d, t), t) ;
} // end of trim
Here it is defined as a global function
inline Parser::parser(string &cmd)
{ .....
string str = trim(s); ......
}
Here the member function trim is called, not the global function.
`Parser::parser(std::string&)':
: undefined reference to `Parser::trim(std::string const&, std::string
const&)'
This is because Parser::trim is declared but not defined.

My guess is that you forgot to qualify the member function name in the definition
as below:
inline string Parser::trim (const string & s, const string & t)
{
string d (s);
return trim_left (trim_right (d, t), t) ;
} // end of trim

Alternatively you may remove the declaration in Parser since trim does not
need to be a Parser member.
 
S

sam

Thierry said:
trim is declarated as a member function of Parser


Here it is defined as a global function


Here the member function trim is called, not the global function.


This is because Parser::trim is declared but not defined.

My guess is that you forgot to qualify the member function name in the
definition as below:



Alternatively you may remove the declaration in Parser since trim does
not need to be a Parser member.
Thanks for the help.
In regarding to moving the trim() stuff to another class, I decided to
create a seperate static class to hold this sort of functions.
Do you think the following static class declaration is fine?
But I m not sure whether a static constructor/destructor is neccessary.

class TextUtil
{
public:
// trim spaces from right (you can define what spaces are)
static string trim_right (const string & s, const string & t =
SPACES);
// trim spaces from left
static string trim_left (const string & s, const string & t =
SPACES);
// trim spaces from both sides
static string trim (const string & s, const string & t = SPACES);

private:
//TextUtil() {};
};

Thanks
Sam
 
O

Old Wolf

sam said:
class TextUtil
{
public:
static string trim_right (const string & s,
const string & t = SPACES);
static string trim_left (const string & s,
const string & t = SPACES);
static string trim (const string & s,
const string & t = SPACES);

private:
//TextUtil() {};
};

It looks like you would be better off with a namespace:

namespace TextUtil
{
string trim_right(const string &s,
const string &t = SPACES);
};

I don't see anything gained by the class-with-static-members
approach over the namespaces approach. But the namespaces
approach gives you the ability to import symbols with 'using'.
 

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,780
Messages
2,569,611
Members
45,279
Latest member
LaRoseDermaBottle

Latest Threads

Top