Error when checking the OS on C++ header file

孤街醉人 提交于 2019-12-12 03:12:08

问题


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 #ifdefing.

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!