问题
I have received some C++ code that I am trying to compile under Linux 64 bits using the provided makefiles.
In that code there is a string_hash.h file containing the code:
#ifndef STRING_HASH
#define STRING_HASH
#include <string>
#include "universal_hash_map.h"
#ifdef WINDOWS
typedef stdext::hash_compare<std::string> String_Hasher;
typedef stdext::hash_map< std::string, std::string, stdext::hash_compare<std::string> > String_Hash;
#else
#ifdef LINUX
class String_Hasher: public stdext::hash< std::string > {
private:
stdext::hash<const char*> hasher;
public:
String_Hasher() {}
size_t operator() (const std::string& p) const {
return hasher(p.c_str());
}
};
typedef stdext::hash_map< std::string, std::string, String_Hasher > String_Hash;
#endif
#endif
#endif
With universal_hash_map.h being:
#include "define_os.h"
#if defined(__MINGW32__) || defined(LINUX)
#include<ext/hash_map>
#define stdext __gnu_cxx;
#else
#if defined(_MSC_VER)
#include<hash_map>
#endif
#endif
and define_os.h:
#if defined(WINDOWS) || defined(LINUX)
#else
#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
|| defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
#define WINDOWS
#elif defined(sun) || defined(__sun) || defined(linux) || defined(__linux) \
|| defined(__linux__) || defined(__CYGWIN__) || defined(BSD) || defined(__FreeBSD__) \
|| defined(__OPENBSD__) || defined(__MACOSX__) || defined(__APPLE__) || defined(sgi) \
|| defined(__sgi)
#define LINUX
#endif
#endif
If I compile the project like that I got the error telling me that the compile can not find stdext::hash
Compiling string_functions.o from /home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_functions.cpp.
In file included from /home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_functions.h:5:0,
from /home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_functions.cpp:1:
/home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_hash.h:12:29: error: expected class-name before ‘;’ token
/home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_hash.h:12:29: error: expected ‘{’ before ‘;’ token
/home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_hash.h:12:35: error: ‘hash’ in namespace ‘::’ does not name a type
/home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_hash.h:21:9: error: ‘__gnu_cxx’ does not name a type
/home/adria/Code/JensAdria/trunk/thirdparty/pechin/Cpp_Libraries/mylibrary/codes/string_hash.h:21:15: error: ‘hash_map’ in namespace ‘::’ does not name a type
make: *** [string_functions.o] Error 1
But what really puzzles me is that if I comment the first line in universal_hash_map.h so it does not include define_os.h, the code compiles fine!
So changing universal_hash_map.h to:
//#include "define_os.h"
#if defined(__MINGW32__) || defined(LINUX)
#include<ext/hash_map>
#define stdext __gnu_cxx;
#else
#if defined(_MSC_VER)
#include<hash_map>
#endif
#endif
or just
//#include "define_os.h"
//#if defined(__MINGW32__) || defined(LINUX)
#include<ext/hash_map>
#define stdext __gnu_cxx;
//#else
//#if defined(_MSC_VER)
//#include<hash_map>
//#endif
//#endif
compiles fine.
However in this last example, if I uncomment *#include "define_os.h"* it does not compile :s
So the question is, why trying to define the OS make the code not to compile?
Also, checking gcc predefined symbols it seems that there's nothing wrong there:
$ gcc -E -dM - </dev/null | grep linux
#define __linux 1
#define __linux__ 1
#define __gnu_linux__ 1
#define linux 1
EDIT: more info about namespaces
In /usr/include/c++/4.7/ext/hash_map (with no file extension) I have:
#ifndef _BACKWARD_HASH_MAP
#define _BACKWARD_HASH_MAP 1
#ifndef _GLIBCXX_PERMIT_BACKWARD_HASH
#include "backward_warning.h"
#endif
#include <bits/c++config.h>
#include <backward/hashtable.h>
#include <bits/concept_check.h>
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
using std::equal_to;
using std::allocator;
using std::pair;
using std::_Select1st;
/**
* This is an SGI extension.
* @ingroup SGIextensions
* @doctodo
*/
template<class _Key, class _Tp, class _HashFn = hash<_Key>,
class _EqualKey = equal_to<_Key>, class _Alloc = allocator<_Tp> >
class hash_map
{
private:
typedef hashtable<pair<const _Key, _Tp>,_Key, _HashFn,
_Select1st<pair<const _Key, _Tp> >,
_EqualKey, _Alloc> _Ht;
_Ht _M_ht;
public:
typedef typename _Ht::key_type key_type;
I don't seem to be able to find the 4.7.3 version of the code that I am running, but here is the 4.7.2 that seems identical to me.
EDIT: Files after running gcc -E on string_functions.cpp:
with error (with include)
without Error (without include)
diff
回答1:
The problem is that you're using a non-standard type, and as such it is not guaranteed to be portable in the way your code has it.
If you can (because your standard library supports it), you should switch to std::unordered_map
. It is mostly a standard, drop-in replacement for the non-standard stdext::hash_map
and it will be platform independent without all the #ifdef
ing.
To test it, you could do something like:
#define stdext std
#define hash_map unordered_map
If it works, then I'd suggest a quick search and replace of your files.
Another solution, is to go hunt down your hash_map header and find out what namespace it's in. It does not appear to be in __gnu_cxx. It might be in stdext, which may be replaced by the preprocessor to be __gnu_cxx.
来源:https://stackoverflow.com/questions/16014944/error-when-checking-the-os-on-c-header-file