为左值和右值的包装器实现C++范围
Implementing a C++ range-for wrapper for lvalues and rvalues
我为循环的范围实现了一个小的辅助包装器,它允许对关联的Qt容器(如QMap
和QHash
(的键和值进行迭代,将每对提取为结构化绑定,例如:
const QMap<int, QString> digitMap = { {1, "one"}, {2, "two"}, {3, "three"} };
for (auto [intKey, strVal] : make_keyval(digitMap)) {
qDebug() << intKey << "->" << strVal;
}
Qt容器不支持开箱即用,因为它们需要使用一对特定的constKeyValueBegin()
和constKeyValueEnd()
方法(假设只有非变异迭代(。因此,我的想法是编写一个简单的包装器类型,它提供一对常规的begin()
和end()
方法,这些方法只需调用容器上的keyValue。
这很容易,但作为一个扩展目标,我还想让包装器可以与临时文件一起使用,比如make_keyval(sometype.toMap())
。主要的挑战是在迭代结束时延长临时对象的生存期,因为我正在处理代理对象。这是我想出的解决方案:
template<typename C>
struct key_value_range_iterator {
key_value_range_iterator(const C& container) : m_rvalueContainer(nullptr), m_containerRef(container) {}
key_value_range_iterator(const C&& container) : m_rvalueContainer(std::make_unique<C>(std::move(container))), m_containerRef(*m_rvalueContainer) {}
typename C::const_key_value_iterator begin() const { return m_containerRef.constKeyValueBegin(); }
typename C::const_key_value_iterator end() const { return m_containerRef.constKeyValueEnd(); }
private:
const std::unique_ptr<C> m_rvalueContainer;
const C& m_containerRef;
};
template<typename C>
auto make_keyval(C&& container) { return key_value_range_iterator(std::forward<C>(container)); }
这似乎对常规变量和临时变量都适用。对于临时性,m_rvalueContainer
用于在迭代期间存储移动的临时性,然后由m_containerRef
引用。在正则变量的情况下,我们只将左值引用直接存储在m_containerRef
中,而不设置m_rvalueContainer
。我验证了在每种情况下都会调用正确的构造函数,并且只有在循环的范围完成后,临时构造函数才会被销毁。
所以我的问题很简单:这是我的包装器的正确实现,还是我遗漏了什么?或者可能有一个我没有想到的角落案例?
注意,在我的初始版本中,我将m_rvalueContainer
作为一个常规值,但我认为这最终会在lvalue情况下免费实例化一个空容器(尽管这对Qt容器来说是一个廉价的操作(,所以我用unique_ptr
替换了它,以确保在这种情况下没有开销。是的,它最终仍然将其初始化为nullptr,但这是可以忽略的。
还有其他意见或建议吗?
由于make_keyval
知道传入的对象是左值还是右值,因此可以将该参数传递到包装器。
#include <type_traits>
template<typename C>
struct key_value_range_iterator {
key_value_range_iterator(const C container) : m_containerRef(container) {}
using iterator = typename std::remove_reference_t<C>::const_key_value_iterator;
iterator begin() const { return m_containerRef.constKeyValueBegin(); }
iterator end() const { return m_containerRef.constKeyValueEnd(); }
private:
const C m_containerRef;
};
template<typename C>
auto make_keyval(C&& container) { return key_value_range_iterator<C>(std::forward<C>(container)); }
当传递左值时,C
被推导为QMap&
,使包装器保持引用。当传递右值时,C
被推导为QMap
,使包装器将右值移动到其成员中。
由于C
可以是QMap&
,我们需要使用std::remove_reference
来成功地获得左值情况的迭代器类型。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- std::random_device是如何实现的