我正在尝试创建一个简单的模板enumerator类,它应该接受:定义了运算符的任何对象,然后再接受表单的打印对(i, v[i]).一个简单的实现如下:
template<typename T>
struct enumerator {
T &v; // reference to minimize copying
enumerator(T &_v) : v(_v) {}
void do_enumerate() {
size_t i = 0;
for(auto x : v) {
cout << i << x << endl;
i++;
}
}
};
Run Code Online (Sandbox Code Playgroud)
这适用于以下事项:
案例A.
vector<int> v({1,2,6,2,4});
auto e = enumerator(v);
e.do_enumerate();
Run Code Online (Sandbox Code Playgroud)
但是,我还希望它能够处理临时对象,例如:
案例B
auto e = enumerator(vector<int>({2,3,9});
e.do_enumerate();
Run Code Online (Sandbox Code Playgroud)
这不起作用,编译器抛出:
no matching function for call to ‘enumerator<std::vector<int> >::enumerator(std::vector<int>)
Run Code Online (Sandbox Code Playgroud)
所以,我试着添加一个
enumerator(T _t) : t(_T) {}
Run Code Online (Sandbox Code Playgroud)
构造函数来解决此错误.现在案例A不起作用,并且出现错误:
error: call of overloaded ‘enumerator(std::vector<int>&)’ is ambiguous
Run Code Online (Sandbox Code Playgroud)
而且,在情况B中,枚举的输出不正确.
解决这个问题的最简洁方法是什么?我会
T t在结构中存储一个不是一个选项)好吧,如果参数是一个右值,我想复制,如果不是,则不复制.那可能吗?
这可以使用make_enumerator如图所示的辅助函数来完成.
template <class T>
struct enumerator {
T v;
enumerator(T&& _v) : v(std::forward<T>(_v)) {}
void do_enumerate() {
size_t i = 0;
for(auto x : v) {
cout << i << x << endl;
i++;
}
}
};
template <class T>
enumerator<T> make_enumerator(T&& x) {
return enumerator<T>(std::forward<T>(x));
}
int main() {
vector<int> v {5, 2, 9, 1};
make_enumerator(v).do_enumerate();
make_enumerator(std::move(v)).do_enumerate();
}
Run Code Online (Sandbox Code Playgroud)
这是如何运作的?
如果参数to make_enumerator是一个类型的左值A然后T被推导为A&并且我们得到了枚举器enumerator<A&>,而如果它是一个类型的右值,A那么T推断为A,我们得到枚举器enumerator<A>.
在第一种情况下,成员enumerator::v将具有类型A&,左值引用绑定到构造函数参数(无复制).在第二种情况下,成员将具有类型A.使用std::forward将参数_v转换为rvalue,因此它将在用于初始化时移动v.