在C++中使用Deduce类型的模板类型跟随我自己的问题,有些人提到通过iterators
引用传递不是惯用的,并且在给定的用例中它不起作用:
templateiterate(Iter &first, Iter &last) { // Do something with the iterators } iterate(container.begin(), container.end()); // error, binding non-const ref to rvalue!
更深入地发现(至少)其他两个主题涉及前者:
通过引用传递C++迭代器有什么问题?
为什么C++ STL容器的开始和结束函数按值而不是常量引用返回迭代器?
但似乎没有问题/答案,通过rvalue引用&&传递迭代器是否(甚至)比通过值传递它们更好.如在
templateiterate(Iter &&first, Iter &&last) { // Do something with the iterators } iterate(container.begin(), container.end());
我的代码使用rvalue引用编译并运行良好,因此我对此有所了解.
首先,像你一样使用单个模板参数意味着如果传递的两个迭代器没有完全相同的类型,模板推导将失败(和相同的值类别,因为这是转发引用).
例如这段代码:
templatesize_t count(Iter &&first, Iter &&last) { ...... } // ... std::string s("hello"); auto s_it = s.begin(); count(s_it, s.end());
实际上编译失败,因为它不知道是否要演绎Iter
到string::iterator&
或string::iterator
.如果要传递一个const_iterator和一个非const迭代器,则会出现类似的问题.
您可以使用两个模板参数来解决此问题.但后来我们开始遇到逻辑错误.
迭代器按值传递是惯用的,因此如果迭代器突然通过引用传递,它可能会让人感到惊讶(因此会引入错误).
例如:
templatesize_t count(It1 &&first, It2 &&last) { size_t c = 0; while ( first != last ) ++first, ++c; return c; } int main() { std::string s("hello"); auto s_it = s.begin(); std::cout << count(s_it, s.end()) << ' '; std::cout << *s_it << '\n'; }
编码器希望在5 h
这里输出,但事实上代码将取消引用结束迭代器,因为你通过s_it
引用传递并且函数修改了它.
当然,count
可以通过拍摄副本来避免这种情况first
......但是现在你浪费了时间和记忆,而不是仅仅通过价值传递.