views:

736

answers:

5

Dear all:

We are programming a logging library that keeps itself in a .hpp file. We would like to include <tr1/unordered_map> (if the compiler supports TR1,) or the standard <map> otherwise. Is there a standard way of checking at compile time if tr1 is available or not?

I was thinking that the same way that the "__cplusplus" define symbol is present, there could have been defined a "__cxx__tr1" or something like that. I haven't seen that in the drafts for TR1, so I assume it is not present, but I wanted to ask first just in case.

As a note, if those defines don't exist, it wouldn't be a bad idea to include them in proposals themselves.

+1  A: 

GCC-4.3 has:

#define __GXX_EXPERIMENTAL_CXX0X__ 1

But, this is obviously not standard.

greyfade
This macro is defined if you use g++ -std=c++0x and then you have unordered_map in std::unordered_map. Otherwise (no -std=c++0x) you do not have this define but you still can use <tr1/unordered_map> include and std::tr1::unordered_map class.
Artyom
Yes, but as others have pointed out, this is something that can only be tested for during configure. All other versions of GCC prior to 4.3 throw an error when that -std switch is given.
greyfade
+1  A: 

One library I deal with needs to use some classes that got added to TR1 from Boost, preferring TR1 if available. The solution (being a Unix-based library) is to shove the checks into the configure script.

So in other words, no, nothing portable that I know of. That said, if you're on Unix, the configure script checks work well enough.

C Pirate
+1  A: 

I think the most standard thing you can do is have the client #define something before including the header =/

#ifdef HAS_TR1
    /* Has TR1 */
#else
    /* Not so much */

I don't know how much of what I'm about to do is allowed, but this is from Ogre:

#if OGRE_COMPILER == OGRE_COMPILER_GNUC && OGRE_COMP_VER >= 310 && !defined(STLPORT)
#   if OGRE_COMP_VER >= 430
#       define HashMap ::std::tr1::unordered_map
#       define HashSet ::std::tr1::unordered_set
#    else
#       define HashMap ::__gnu_cxx::hash_map
#       define HashSet ::__gnu_cxx::hash_set
#    endif
#else
#   if OGRE_COMPILER == OGRE_COMPILER_MSVC
#       if OGRE_COMP_VER > 1300 && !defined(_STLP_MSVC)
#           define HashMap ::stdext::hash_map
#           define HashSet ::stdext::hash_set
#       else
#           define HashMap ::std::hash_map
#           define HashSet ::std::hash_set
#       endif
#   else
#       define HashMap ::std::hash_map
#       define HashSet ::std::hash_set
#   endif
#endif

Tell me if that should be removed and I should just say "Check out Ogre". Seems like it's just a multi-compiler version of greyfades non-standard solution.

GMan
+2  A: 

If you are using any configuration tools like autotools you may try to write a test like:

AC_CHECK_HEADER(tr1/unordered_map,[AC_DEFINE([HAVE_TR1],[],["Have tr1"])],[])
AC_CHECK_HEADER(unordered_map,[AC_DEFINE([HAVE_CXX0X],[],["Have C++0x"])],[])

And then use these defines in your code.

Generally speaking __cplusplus macro should give you standard version number, but there is no compiler that gives you 100% standard implementation... Thus write configure macros.

Unfortunately this is only quite reliable way to check such things unless you want to write 1001 #ifdef for each compiler (what boost does)

And then:

#include "config.h"
#ifdef  HAVE_CXX0X
#  include <unordered_map>
   typedef std::unordered_map<foo,bar> my_map;
#elif HAVE_TR1
#  include <tr1/unordered_map>
   typedef std::tr1::unordered_map<foo,bar> my_map;
#else
#  include <map>
   typedef std::map<foo,bar> my_map;
#endif
Artyom
OK, that was an option I wanted to avoid, as I want just to release a .hpp file and run. For these "almost standard" things, I would prefer a simple comparison rather than having to run a full-fledged configure.
Diego Sevilla
I'm accepting this answer as it seems there is no way, and this seems to be the better way...
Diego Sevilla
+1  A: 

See ISO C++ (WG21) paper N1575. This paper has been dropped from TR1, with no replacement. So there is no official way to detect TR1.

MSalters
+1. Interesting. I didn't know... Pity.
Diego Sevilla