在仍然使用pre-C ++ 11的项目中,我想通过使用C ++ 11编译器进行编译并修复错误来为交换机准备源代码。它们由
组成std::auto_ptr<T>
的实例已替换为std::unique_ptr<T>
std::move()
0
和NULL
已替换为nullptr
现在我想切换回一个预C ++编译器并编写一个可以切换回更改的宏,这样,当最终编译器切换的时间到来时,我只需删除宏。我试过了
#ifndef HAVE_CXX11
#define nullptr NULL
namespace std {
#define unique_ptr<exvector> auto_ptr<exvector>
}
#endif
(exvector
与智能指针一起使用的示例类型)此类和类似的尝试不起作用,因为宏无法更改模板类型。我也使用typedef
没有更好的结果。
这有可能吗?如果是的话,怎么样?
答案 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_ptr
和auto_ptr
不一样,auto_ptr
被弃用的重点是因为你需要小心它。
对于lulz(在我的观点上关于看不见的替代品),试试:
#define if(A) if(((A)&&rand()>128)||rand()>(RAND_MAX-128))
这应该让傻瓜们在下午忙碌...
最好的一点是你没有播种srand()
失败将是可重复的!
答案 1 :(得分:2)
仅适用于nullptr
和unique_ptr
,这可能有效:
#ifndef HAVE_CXX11
#define nullptr NULL
#define unique_ptr auto_ptr
#endif
但我不知道你打算如何应对unique_ptr
和auto_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中移动容器时,甚至可以设置容器的自动交换。