用于在 auto_ptr 和 unique_ptr 之间切换的宏
macro for switching between auto_ptr and unique_ptr
在一个仍然使用 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
没有更好的结果。
这是否可能,如果可能,如何实现?
对于 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
添加任何内容。但如果只是临时措施,应该是安全的(pre-11的编译器不太可能有std::move
这个名字)。
怎么样
#ifdef NOT_HAVING_CPP_11
namespace std{
template<typename T>
struct unique_ptr : public auto_ptr<T>{}; }
#endif
这样,在将旧代码中的所有 auto_ptr 实例替换为 unique_ptr 后,您可以删除 NOT_HAVING_CPP_11 宏,并且在现代编译器上编译时不会发出警告.
#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
教给return一个lvalue_up
,让up
拒绝从up
中复制C++03 模式(手动移动语义)。当您在 C++03 中从容器移动时,您甚至可以在容器上设置自动交换。
我会引入非常明确的宏,例如
//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
为什么?因为即使是不经意的 reader 也会看到一些替换正在进行。
是的,代码看起来很丑但是很安全"not going to blow anyone's fingers off ugly"。我们是工程师而不是诗人,这就是我们的美!
但是我不得不说我同意发帖者认为你应该对代码进行分支的观点。这不是唯一的不兼容性,你的代码会变得越来越臃肿,你可能会发现你正在做更多的工作(并引入更多的错误)试图使单个分支多目标而不是分支。
宏是美妙的东西,但任何形式:
#define <common symbol> <something else>
需要 100% 保证良性 "you don't need to know it was substituted" 才能被宽恕。
我只是不认为:
#define unique_ptr auto_ptr
或任何其他使此替换不可见的东西都完全通过了该测试。
unique_ptr
和 auto_ptr
不一样, auto_ptr
被弃用的全部原因是你需要小心使用它。
对于 lulz(回到我关于隐形替代品的观点)尝试:
#define if(A) if(((A)&&rand()>128)||rand()>(RAND_MAX-128))
这应该能让这些混蛋们忙一下午……
最好的一点是你没有播种 srand()
失败将是可重复的!
在一个仍然使用 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
没有更好的结果。
这是否可能,如果可能,如何实现?
对于 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
添加任何内容。但如果只是临时措施,应该是安全的(pre-11的编译器不太可能有std::move
这个名字)。
怎么样
#ifdef NOT_HAVING_CPP_11
namespace std{
template<typename T>
struct unique_ptr : public auto_ptr<T>{}; }
#endif
这样,在将旧代码中的所有 auto_ptr 实例替换为 unique_ptr 后,您可以删除 NOT_HAVING_CPP_11 宏,并且在现代编译器上编译时不会发出警告.
#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
教给return一个lvalue_up
,让up
拒绝从up
中复制C++03 模式(手动移动语义)。当您在 C++03 中从容器移动时,您甚至可以在容器上设置自动交换。
我会引入非常明确的宏,例如
//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
为什么?因为即使是不经意的 reader 也会看到一些替换正在进行。
是的,代码看起来很丑但是很安全"not going to blow anyone's fingers off ugly"。我们是工程师而不是诗人,这就是我们的美!
但是我不得不说我同意发帖者认为你应该对代码进行分支的观点。这不是唯一的不兼容性,你的代码会变得越来越臃肿,你可能会发现你正在做更多的工作(并引入更多的错误)试图使单个分支多目标而不是分支。
宏是美妙的东西,但任何形式:
#define <common symbol> <something else>
需要 100% 保证良性 "you don't need to know it was substituted" 才能被宽恕。
我只是不认为:
#define unique_ptr auto_ptr
或任何其他使此替换不可见的东西都完全通过了该测试。
unique_ptr
和 auto_ptr
不一样, auto_ptr
被弃用的全部原因是你需要小心使用它。
对于 lulz(回到我关于隐形替代品的观点)尝试:
#define if(A) if(((A)&&rand()>128)||rand()>(RAND_MAX-128))
这应该能让这些混蛋们忙一下午……
最好的一点是你没有播种 srand()
失败将是可重复的!