基于宏的C ++头选择

时间:2010-12-22 14:22:11

标签: c++ macros header-files

我目前正在编写一个C ++库,需要使用GCC for Linux和Sun CC for Solaris进行编译。为了性能,我创建了一些基于编译器选择不同头的类; GCC使用c ++ 0x或TR1或使用niether和Sun CC RogueWave或STLPort。我正在努力找出#ifdef类型定义的最佳方法,例如:

namespace project {

    #if defined(__GNUG__)
        #if defined(HAVE_CXXOX)
            #include <unorderd_map>
            typedef srd::unordered_map map;
        #elif defined(HAVE_TR1)
            #include <tr1/unordered_map>
            typedef std::tr1::unordered_map map;
        #else
            #include <map>
            typedef std::map map;
        #endif
    #elif defined(__SUNPROC_CC)
        #include <map>
        typedef std::map map;
    #endif

} //namespaces

3 个答案:

答案 0 :(得分:3)

这不会有两个原因:

  1. 标题必须包含在namespace project { ... }范围之外。 (如果标题只包含模板和内联函数,它可能无论如何都可以工作,但我不会指望它。)
  2. typedef不适用于模板。您可以在其中定义一个空的派生类。
  3. 所以也许是这样的:

    #if defined(__GNUG__)
        #if defined(HAVE_CXXOX)
            #include <unordered_map>
            #define MAP std::unordered_map
        #elif defined(HAVE_TR1)
            #include <tr1/unordered_map>
            #define MAP std::tr1::unordered_map
        #else
            #include <map>
            #define MAP std::map
        #endif
    #elif defined(__SUNPROC_CC)
        #include <map>
        #define MAP std::map
    #endif
    
    namespace myproject {
        template <class K, class V>
        class map : public MAP<K, V> {};
    }
    
    #undef MAP
    

答案 1 :(得分:0)

在进一步阅读之后,可能值得研究C ++ 0x中新的“模板别名”概念。这里有一些未经测试的代码作为它如何工作的一个例子。

#if defined(__GNUG__)
       #if defined(HAVE_CXXOX)
           #include <unordered_map>
           #define MAP std::unordered_map
       #elif defined(HAVE_TR1)
           #include <tr1/unordered_map>
           #define MAP std::tr1::unordered_map
       #else
           #include <map>
           #define MAP std::map
       #endif
#elif defined(__SUNPROC_CC)
    #include <map>
    #define MAP std::map
#endif

namespace internal {

    template <typename K, typename V>
    struct unordered_map { typedef MAP<K, V>; >;

} //internal

template <typename K, typename V>
using unordered_map = typename internal::unordered_map<K, V>::type;

有关详情,请参阅此处http://www2.research.att.com/~bs/C++0xFAQ.html#template-alias

答案 2 :(得分:0)

在定义和包含的棘手之间以及测试几乎每个编译器的必要性,更不用说次要版本和东西(例如:tuple_element在某些特定版本的GCC中具有其他名称的东西),我采取了理智的方法:将解决方案委托给实际拥有选择权和实施权的人。这意味着使用像Boost.TR1这样的包装器或者“自己动手”。

我假设标题路径与C ++ 11类似,就像在#include <header>中一样编写代码。用户比我更了解他自己的环境,因此他将能够例如:add Boost.TR1 to the include paths(或他选择的另一个TR1实现)使事情更加无缝地工作。哎呀,即使只是指向一个带有“重定向”标题的文件夹,如果需要,它只会转发到<tr1/*>版本。等等。基本上,如果开发人员已经为你做出了牺牲,为什么要自己经历宏观噩梦呢?

这让我背上了很多痛苦,因为它允许我编写“一次编写”代码,而不必每次都测试不同的编译器,即使是次要版本,也有助于使我的代码向前兼容C ++ 11

当然,它有一些技巧 - 取决于你对你的编译器有什么假设,你可能需要使用像“using namespace tr1”黑客或(更好)交替等其他技巧同类