Compiling with g++ 3.0

L

Luc Mazardo

The following code works with g++ 2.75 but
i've some troubles with compiling with g++ 3.0.

Thanks in advance if you have a solution.

Here is the error message.

main.hpp:28: specializing `struct std::hash<std::string>' in different
namespace
/usr/include/g++-v3/ext/stl_hash_fun.h:68: from definition of `template<class
_Key> struct std::hash'
make: *** [resource_identifier.lo] Error 1


#include <pair.h>
#include <string>
#include <map>
#include <vector>


#ifdef __GNUC__ /* grabbed in libstdc++ faq */
#if __GNUC__ < 3
#include <hash_map.h>
namespace Sgi { using ::hash_map; }; // inherit globals
#else
#include <ext/hash_map>
#if __GNUC_MINOR__ == 0
namespace Sgi = std; // GCC 3.0
#else
namespace Sgi = ::__gnu_cxx; // GCC 3.1 and later
#endif
#endif
#else // ... there are other compilers, right?
namespace Sgi = std;
#endif


using namespace std;


//TODO: include this definition in the Hashtable class
template<> struct hash<string>
{
size_t operator()(const string& s) const
{
return hash<char const*>()(s.c_str());
}
};


#ifdef NAMESPACES
namespace foobar {
#endif

class NoSuchElementException
{
public:
NoSuchElementException(string w) {_what = w;}
virtual ~NoSuchElementException() {}
virtual string what() { return _what; }
private:
string _what;
};
template <class T> class Hashtable //: public ost::Conditional
{
public:
Hashtable() {} //: Conditional() {}

virtual ~Hashtable() {clear(); }
virtual T put(const string& key, T value)
{
assert(key.c_str() != NULL); //TODO: must throw ?

// enterMutex();
T returnValue = mHashtable[key];
mHashtable[key] = value;
// leaveMutex();

return returnValue;
}

virtual T get(const string& key) throw (NoSuchElementException)
{
assert(key.c_str() != NULL); //TODO: must throw ?
// enterMutex();

if (mHashtable.empty())
{
// leaveMutex ();
throw NoSuchElementException (key);
}

if (mHashtable.find(key) == mHashtable.end())
{
// leaveMutex();
throw NoSuchElementException(key);
}

T returnValue = mHashtable[key];
//leaveMutex();

return returnValue;
}
virtual void del(const string& key) throw (NoSuchElementException)
{
assert(key.c_str() != NULL); //TODO: must throw ?
// enterMutex();

if (mHashtable.find(key) == mHashtable.end()) {
// leaveMutex();
throw NoSuchElementException(key);
}
mHashtable.erase (key);
// leaveMutex();

return;
}
virtual void clear() {
// enterMutex();
mHashtable.erase(mHashtable.begin(), mHashtable.end());
// leaveMutex();
}

virtual bool isEmpty () {
bool ret;
// enterMutex();
ret = mHashtable.empty ();
// leaveMutex();
return ret;
}

virtual vector<pair<string,T> > toVector()
throw (NoSuchElementException)
{
vector <pair<string, T> > v;
// enterMutex();

if (mHashtable.empty()) {
// leaveMutex();
throw NoSuchElementException(string("hashtable is empty"));
}



for(hash_map<string, T , hash<string> >::iterator iter
= mHashtable.begin(); iter != mHashtable.end(); ++iter)
{
pair <string, T> p(*iter);// (iter->first, iter->second);
v.insert(v.begin(), p);
}

//leaveMutex();
return v;
}

protected:
hash_map<string, T, hash<string> > mHashtable;
};

int
main(void)
{
Hashtable<int> h;

return 0;
}
#ifdef NAMESPACES
}; // foobar
#endif

/** EMACS **
* Local variables:
* mode: c++
* c-basic-offset: 4
* End:
*/

Here is my release of g++ 3.0:
$ g++-3.0 -v
Reading specs from /usr/lib/gcc-lib/i386-linux/3.0.4/specs
Configured with: ../src/configure -v
--enable-languages=c,c++,java,f77,proto,objc
--prefix=/usr --infodir=/share/info --mandir=/share/mx
Thread model: posix
gcc version 3.0.4

Here is my release of g++ 2.95:
g++ -v
Reading specs from /usr/lib/gcc-lib/i386-linux/2.95.4/specs
gcc version 2.95.4 20011002 (Debian prerelease)
 
G

Gianni Mariani

Luc said:
The following code works with g++ 2.75 but
i've some troubles with compiling with g++ 3.0.

Thanks in advance if you have a solution.

Here is the error message.

main.hpp:28: specializing `struct std::hash<std::string>' in different
namespace
/usr/include/g++-v3/ext/stl_hash_fun.h:68: from definition of `template<class
_Key> struct std::hash'
make: *** [resource_identifier.lo] Error 1

hash_map is not part of STL and so the gcc team ( in an effort to be
standards compliant) moved the hash* templates into the __gnu_cxx
namespace. The gcc 3.x series is also more standards compliant and so
you'll need to fix some gcc 2.9x things.
#include <pair.h>
^^^^^^^^ don't need this header - std::pair is found in std::map and
pair.h is non-standard
#include <string>
#include <map>
#include <vector>


#ifdef __GNUC__ /* grabbed in libstdc++ faq */
#if __GNUC__ < 3
#include <hash_map.h>
namespace Sgi { using ::hash_map; }; // inherit globals
#else
#include <ext/hash_map>
#if __GNUC_MINOR__ == 0
namespace Sgi = std; // GCC 3.0
#else
namespace Sgi = ::__gnu_cxx; // GCC 3.1 and later
#endif
#endif
#else // ... there are other compilers, right?
namespace Sgi = std;
#endif


using namespace std;

using namespace __gnu_cxx;


//TODO: include this definition in the Hashtable class
namespace __gnu_cxx
{
template<> struct hash<string>
{
size_t operator()(const string& s) const
{
return hash<char const*>()(s.c_str());
}
};
};



#ifdef NAMESPACES
namespace foobar {
#endif

class NoSuchElementException
{
public:
NoSuchElementException(string w) {_what = w;}
virtual ~NoSuchElementException() {}
virtual string what() { return _what; }
private:
string _what;
};
template <class T> class Hashtable //: public ost::Conditional
{
public:
Hashtable() {} //: Conditional() {}

virtual ~Hashtable() {clear(); }
virtual T put(const string& key, T value)
{
assert(key.c_str() != NULL); //TODO: must throw ?

// enterMutex();
T returnValue = mHashtable[key];
mHashtable[key] = value;
// leaveMutex();

return returnValue;
}

virtual T get(const string& key) throw (NoSuchElementException)
{
assert(key.c_str() != NULL); //TODO: must throw ?
// enterMutex();

if (mHashtable.empty())
{
// leaveMutex ();
throw NoSuchElementException (key);
}

if (mHashtable.find(key) == mHashtable.end())
{
// leaveMutex();
throw NoSuchElementException(key);
}

T returnValue = mHashtable[key];
//leaveMutex();

return returnValue;
}
virtual void del(const string& key) throw (NoSuchElementException)
{
assert(key.c_str() != NULL); //TODO: must throw ?
// enterMutex();

if (mHashtable.find(key) == mHashtable.end()) {
// leaveMutex();
throw NoSuchElementException(key);
}
mHashtable.erase (key);
// leaveMutex();

return;
}
virtual void clear() {
// enterMutex();
mHashtable.erase(mHashtable.begin(), mHashtable.end());
// leaveMutex();
}

virtual bool isEmpty () {
bool ret;
// enterMutex();
ret = mHashtable.empty ();
// leaveMutex();
return ret;
}

virtual vector<pair<string,T> > toVector()
throw (NoSuchElementException)
{
vector <pair<string, T> > v;
// enterMutex();

if (mHashtable.empty()) {
// leaveMutex();
throw NoSuchElementException(string("hashtable is empty"));
}



for(hash_map<string, T , hash<string> >::iterator iter

Need to use typename - like this:
 
D

Donovan Rebbechi

Luc Mazardo wrote:
^^^^^^^^ don't need this header - std::pair is found in std::map and
pair.h is non-standard

For someone who wants to use pair and doesn't need map/multimap, the
<utility> header. This header just defines std::pair and std::relops

Cheers,
 
D

Donovan Rebbechi

assert(key.c_str() != NULL); //TODO: must throw ?

This is a silly test. If s is a string, s.c_str() is never NULL,
because that function is guaranteed to return a valid '\0'-terminated
c string.

Is there a reason why you're declaring all of those virtual member
functions ? It seems inappropriate for this class.

Cheers,
 
B

Bret Pehrson

Is there a reason why you're declaring all of those virtual member
functions ? It seems inappropriate for this class.

Every non-private method should be virtual.
 
G

Gianni Mariani

gcc 3.4 (pre-release) reports it as a "non standard" header.

For someone who wants to use pair and doesn't need map/multimap, the
<utility> header. This header just defines std::pair and std::relops

That would be nice - I think the way to do this is to #include said:

... same
 
R

red floyd

Bret said:
Every non-private method should be virtual.

I disagree. Consider the case where you have to do some common
startup/cleanup around a virtual function. I'd actually make the
virtual as a protected. See below. I'd argue that you don't want to
make Base::f() a virtual.

class Base
{
private:
void setup();
void cleanup();
protected:
virtual void do_work();
public:
void f()
{
setup();
do_work();
cleanup();
}

// other methods redacted
};
 
D

Donovan Rebbechi

Every non-private method should be virtual.

That's another way of saying that every class (or at least every
container class) should be designed for extension via public inheritance.
What's your basis for this belief ? Or, if I've mischaracterised your
opinion, what is it about the hash map that makes it a better candidate
for subclassing than other classes, or other container classes ?

Note that the standard container classes do not use virtual methods. Why
not ? In your opinion, did the standards committee simply get it wrong ?

Since it is in your opinion advantageous to make these containers
subclassable, could you provide some good examples of useful derived classes ?

On to the problems of making methods virtual:

How do you write a "virtual" assignment operator ?

For example, what does this code do ?

HashBase h1;
HashDerived h2;

h1 = h2;

The problem is that you can treat a class like a "value" or a "reference".
"value" classes can be assigned to. Classes that are handled via reference
may be copyable, but you can't treat them as (assignable) values. You need
to wrap them in a "handle"/"envelope"/"pimpl" class to do that. Which adds
indirection.

Cheers,
 
R

Rolf Magnus

Bret said:
Every non-private method should be virtual.

Heh, I've seen people write that every virtual function should be
private, and that makes more sense than what you write.
Anyway, may I ask what the reason for your above statement is?
 
D

David Harmon

I disagree. Consider the case where you have to do some common
startup/cleanup around a virtual function. I'd actually make the
virtual as a protected.

If that is your reason, you should make the virtual function private.
You don't want subclasses calling it without the common startup/cleanup
any more than you want foreigners to do so.
 
B

Bret Pehrson

Not a troll.

Let me maybe qualify my statement:

Resuable (non-template) classes should seriously consider all non-private
methods as virtual.

Reason for my statement: I'm tired of using class libraries that impose all
sorts of arbitrary restrictions because methods aren't virtual (but should be).

I'd rather that a class was needlessly loaded down w/ virtual methods than not.
 
B

Bret Pehrson

Why is do_work protected?

The **ONLY** reason that something should be declared protected is to indicate
that the class is suitable for derivation, and that method has some potential
value to the derived class.
 
B

Bret Pehrson

I'd be interested to hear why a virtual function should be private.

Let me expand a little: every (non-template) class that isn't expressly not
intended for derivation should by default have all non-private methods declared
virtual.

How many times have you used a class outside of your direct source manipulation
control (library or otherwise) that didn't have one or more virtual methods,
but that was suitable for derivation? Let's discuss the hacks that must be
used to attempt to overcome this in code...
 
L

lilburne

Bret said:
I'd rather that a class was needlessly loaded down w/ virtual methods than not.

The problem with virtual functions is that people can
override them in derived classes. Now sometimes this is a
good thing because people can specialize the behaviour for
the subclass in hand. Unfortunately they can also warp the
behaviour such that the overridden function does something
totally different from the original behaviour.

The more you refuse to fix a classes hierarchies behaviour
by making the functions virtual the more scope you allow for
the above mistake to occur. By making the entire behaviour
of your class hierarchy fluid the less confidence you have
that the subclasses are indeed homogenous.
 
B

Bret Pehrson

The problem with virtual functions is that people can
override them in derived classes.

"Problem"??? The **OPTION** to override is the *whole* point.
Now sometimes this is a
good thing because people can specialize the behaviour for
the subclass in hand. Unfortunately they can also warp the
behaviour such that the overridden function does something
totally different from the original behaviour.

True, but at least they have the *OPTION* to do that. Don't protect me from
myself.
The more you refuse to fix a classes hierarchies behaviour
by making the functions virtual the more scope you allow for
the above mistake to occur. By making the entire behaviour
of your class hierarchy fluid the less confidence you have
that the subclasses are indeed homogenous.

As a class designer, it isn't my problem if the derivatives are misused -- that
is the class user's problem.
 
R

Rolf Magnus

Bret said:
I'd be interested to hear why a virtual function should be private.

To be able to check for pre- and post conditions in the base class
wihout the derived classes needing to call any extra functions. Didn't
you ever get into a situation where your derived class's virtual
function absolutely _needs_ to call the one from the base class or
another member function of it for your code to work? Better let the
base class always handle it, by doing something like:

class Base
{
public:
void foo(int x); // x _must_ always lower than 100
private:
virtual void do_foo(int x) = 0;
};

void Base::foo(int x)
{
if (x>=100) throw std::range_error();
do_foo(x);
}

class Derived : public Base
{
private:
void do_foo(int x);
};

void Derived::do_foo(int x)
{
// no need to care for range here
}

do_foo is private because it's not supposed to be called directly.
A real world example for post conditions could be a window object that
gets events, and those events must propagate up the inheritance
hierarchy. Instead of letting the one who derived remember calling the
base class's function, you already care for that in the base class.
And some people say that the above should always be done so that you can
(also later if needed e.g. for a bug fix) easily add pre- and post
condition check in the base class without the need to change all the
classes derived from it, which might actually be out of your control if
you're implementing a library or a plugin framework.
Let me expand a little: every (non-template) class that isn't
expressly not intended for derivation should by default have all
non-private methods declared virtual.

I wonder why you exclude templates.
How many times have you used a class outside of your direct source
manipulation control (library or otherwise) that didn't have one or
more virtual methods,
but that was suitable for derivation?

Actually not very often, but it did indeed happen. But to my experience,
it was obvious that those functions should have been made virtual in
the base class. There are most often other functions that obviously
don't need to be virtual.
Let's discuss the hacks that must be used to attempt to overcome this
in code...

I really didn't have to deal that much with it to get a knowledge about
those :)
 
L

lilburne

Bret said:
True, but at least they have the *OPTION* to do that. Don't protect me from
myself.


Its not a question about protecting you from yourself. Its a question
of protecting those that come after you.

As a class designer, it isn't my problem if the derivatives are misused -- that
is the class user's problem.

By making everything virtual you haven't designed a class. What you have
done is provide a namespace for a bunch of function to reside in. Your
class has no predictable behaviour it is simply an interface (which in
some cases is fine). You are in effect saying that there is nothing
concrete that defines what this class is, and what you end up with is
either a blamanche or java.
 
B

Bret Pehrson

Its a question of protecting those that come after you.

That is equivalent as protecting me from myself; or more generally, protecting
someone from themself.
You are in effect saying that there is nothing
concrete that defines what this class is, and what you end up with is
either a blamanche or java.

You make it sound like these classes are just arbitrarily floating around in
nether-space, and by pure happenstance create something.

The base class is well defined. The derived class(es) is(are) well defined.
What isn't defined?

I don't know what "blamanche" is.
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top