我正在尝试创建一个简单的模板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++;
}
}
};
对于以下情况,这可以正常工作:
案例A
vector<int> v({1,2,6,2,4});
auto e = enumerator(v);
e.do_enumerate();
但是,我也希望它处理类似以下的临时对象:
案例B
auto e = enumerator(vector<int>({2,3,9});
e.do_enumerate();
这不起作用,编译器将抛出:
no matching function for call to ‘enumerator<std::vector<int> >::enumerator(std::vector<int>)
因此,我尝试添加一个
enumerator(T _t) : t(_T) {}
构造函数来解决此错误。现在,情况A不起作用,并且出现错误:
error: call of overloaded ‘enumerator(std::vector<int>&)’ is ambiguous
此外,在情况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();
}
如何运作?
如果
make_enumerator
的参数是A
类型的左值,则T
推导为A&
,我们得到枚举器enumerator<A&>
,而如果它是A
类型的右值,则T
推导为A
,我们得到枚举器enumerator<A>
。在第一种情况下,成员
enumerator::v
的类型将为A&
,该值是绑定(bind)到构造函数参数的左值引用(不复制)。在第二种情况下,成员的类型将为A
。 std::forward
的使用将参数_v
强制转换为一个右值,因此它将在用于初始化v
时从其移开。关于c++ - 如何在模板中存储右值或左值引用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24175279/