用于在auto_ptr和unique_ptr之间切换的宏

时间:2015-05-26 15:23:52

标签: c++ c++11 macros unique-ptr

在仍然使用pre-C ++ 11的项目中,我想通过使用C ++ 11编译器进行编译并修复错误来为交换机准备源代码。它们由

组成
  • std::auto_ptr<T>的实例已替换为std::unique_ptr<T>
  • 必要时,使用std::move()
  • 包装智能指针
  • 部分0NULL已替换为nullptr

现在我想切换回一个预C ++编译器并编写一个可以切换回更改的宏,这样,当最终编译器切换的时间到来时,我只需删除宏。我试过了

#ifndef HAVE_CXX11
#define nullptr NULL
namespace std {
#define unique_ptr<exvector> auto_ptr<exvector>
}
#endif

exvector与智能指针一起使用的示例类型)此类和类似的尝试不起作用,因为宏无法更改模板类型。我也使用typedef没有更好的结果。

这有可能吗?如果是的话,怎么样?

4 个答案:

答案 0 :(得分:3)

我会介绍非常明确的宏,如

//Defines to overcome pre C++11 limitations regarding 
//std::auto_ptr and absence of 'good' move (i.e. std::move) semantics.
//Strictly post C++11 code should use std::unique_ptr and std::move explicitly.
//All other code should use the macros.
//If pre-C++11 ceases to be a target the macros may be replaced...
#ifdef HAVE_CXX11 //Or whatever...

#define UNIQUE_PTR_TYPE std::unique_ptr
#define MOVE_UNIQUE_PTR(PTR) std::move(PTR)

#else

#define UNIQUE_PTR_TYPE std::auto_ptr
#define MOVE_UNIQUE_PTR(PTR) (PTR)

#endif

为什么呢?因为即使是偶然的读者也会看到一些替代品正在进行中。

是的,代码看起来会很难看但是安全的“不会让任何人的手指变得丑陋”。我们工程师不是诗人,这就是我们的美丽!

但是我不得不说我同意那个认为你应该分支代码的海报。这不是唯一的不兼容性,并且您的代码将变得越来越臃肿,您可能会发现您正在做更多的工作(并引入更多错误)尝试创建单个分支多目标而不是分支。

宏是很棒的东西,但形式如下:

#define <common symbol> <something else>

需要100%保证良性“你不需要知道它被替代”才能被宽恕。

我只是不认为:

#define unique_ptr auto_ptr

或者使这种替换不可见的任何其他东西都通过了那个测试。 unique_ptrauto_ptr不一样,auto_ptr被弃用的重点是因为你需要小心它。

对于lulz(在我的观点上关于看不见的替代品),试试:

#define if(A) if(((A)&&rand()>128)||rand()>(RAND_MAX-128))

这应该让傻瓜们在下午忙碌... 最好的一点是你没有播种srand()失败将是可重复的!

答案 1 :(得分:2)

仅适用于nullptrunique_ptr,这可能有效:

#ifndef HAVE_CXX11
  #define nullptr NULL
  #define unique_ptr auto_ptr
#endif

但我不知道你打算如何应对unique_ptrauto_ptr的不同语义。

如果您愿意暂时处理一些未定义的行为(不太可能导致实际问题),您还可以提供自己的std::move

namespace std {

template <class T>
T& move(T &x) { return x; }

}

这是UB,因为你不允许向namespace std添加任何内容。但如果它只是一个临时措施,它应该是安全的(11之前的编译器不太可能有名称std::move)。

答案 2 :(得分:0)

怎么样

cat

这样,在使用unique_ptr替换旧代码上的所有auto_ptr实例后,可以删除NOT_HAVING_CPP_11宏,并在现代编译器上编译时不会发出警告。

答案 3 :(得分:0)

#if no_Cxx11
  template<class T>
  struct up:auto_ptr<T> {
    up(T* t):auto_ptr(t) {}
    up(auto_ptr& o):auto_ptr(o) {}
  };
  T& my_move(T& t){return t;}
  struct my_nullptr_t {
    template<class T>
    operator T*()const{return NULL;}
    // template operator T* isn't always looked for:
    operator void*()const{return NULL;}
  };
  static const my_nullptr_t nullptr;
#else
  template<class T>
  using up=std::unique_ptr<T>;
  template<class T>
  decltype(std::move(std::declval<T>()))
  my_move(T&& t) {
    return std::move(std::forward<T>(t));
  }
  using my_nullptr_t = std::nullptr_t;
#endif

这需要将std::unique_ptr替换为up,将std::nullptr_t替换为my_nullptr_t,将std::move替换为代码库中的my_move。在C ++ 11中,它们都是C ++ 11。在C ++ 03中,它们是模拟的。

您甚至可以更进一步,并教my_move返回lvalue_up,并让up拒绝在C ++ 03模式下从up复制(手动移动语义)。当您在C ++ 03中移动容器时,甚至可以设置容器的自动交换。