C++11“move ”是一个不错的功能,但我发现当与“复制”同时使用时很难避免代码重复(我们都讨厌这个)。下面的代码是我实现的一个简单的循环队列(不完整),两个push()方法除了一行外几乎一样。
我遇到过很多类似的情况。任何想法如何在不使用宏的情况下避免这种代码重复?
=== 编辑 ===
在这个特定示例中,可以将重复的代码重构出来并放入单独的函数中,但有时这种重构不可用或不容易实现。
#include <cstdlib>
#include <utility>
template<typename T>
class CircularQueue {
public:
CircularQueue(long size = 32) : size{size} {
buffer = std::malloc(sizeof(T) * size);
}
~CircularQueue();
bool full() const {
return counter.in - counter.out >= size;
}
bool empty() const {
return counter.in == counter.out;
}
void push(T&& data) {
if (full()) {
throw Invalid{};
}
long offset = counter.in % size;
new (buffer + offset) T{std::forward<T>(data)};
++counter.in;
}
void push(const T& data) {
if (full()) {
throw Invalid{};
}
long offset = counter.in % size;
new (buffer + offset) T{data};
++counter.in;
}
private:
T* buffer;
long size;
struct {
long in, out;
} counter;
};
最佳答案
这里最简单的解决方案是使参数成为转发引用。这样您就可以只使用一个功能:
template <class U>
void push(U&& data) {
if (full()) {
throw Invalid{};
}
long offset = counter.in % size;
// please note here we construct a T object (the class template)
// from an U object (the function template)
new (buffer + offset) T{std::forward<U>(data)};
++counter.in;
}
虽然方法有缺点:
它不是通用的,也就是说它不能总是完成(以微不足道的方式)。例如,当参数不像 T 那样简单时(例如
SomeType<T>
)。你延迟了参数的类型检查。当使用错误的参数类型调用 push 时,可能会出现冗长且看似无关的编译器错误。
顺便说一下,在你的例子中 T&&
不是转发引用。这是一个右值引用。那是因为 T 不是函数的模板参数。它属于类,因此在实例化类时已经推导出来。所以编写代码的正确方法是:
void push(T&& data) {
...
... T{std::move(data)};
...
}
void push(const T& data) {
... T{data};
...
}
关于c++ - 使用 C++11 复制和 move 时避免代码重复,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34461376/