提问人:PythonLinski 提问时间:12/11/2020 最后编辑:PythonLinski 更新时间:12/11/2020 访问量:331
如何将单个对象转换为 boost::any_range?
How to convert a single object to a boost::any_range?
问:
我正在尝试创建并返回仅包含一个对象的 boost:any_range(我不知道这是否是核心问题),但我收到以下错误:
- 错误 C2893:无法专用化函数模板 'range_iterator<C,void>::type boost::range_adl_barrier::begin(T &)'
- 注意:使用以下模板参数:
- 注意: 'T=const WrappedRange'
- 错误 C2672:“end”: 未找到匹配的重载函数
- 错误 C2893:无法专用函数模板
“range_iterator<C,void>::type boost::range_adl_barrier::end(T &)” - 注意:使用以下模板参数: 注意: 'T=const
WrappedRange'
您可以在下面找到相关的代码片段:
- 这是我想调用的函数,在编译过程中失败:
const HandleRange BasicCollection::GetPartHandles() const
{
return HandleRange
//return -> also tried this
{
Handle(GenericHandleManager::CreatePartHandleValue(GenericHandleManager::GetPartIdx(_collectionHandle)))
};
}
不知何故,这有效,但这并不干净:
const HandleRange BasicCollection::GetPartHandles() const
{
auto container = { _collectionHandle };
return container | boost::adaptors::transformed([collectionHandle = _collectionHandle](const auto & index_value)
{
return HandleRange::value_type
{
Handle(GenericHandleManager::CreatePartHandleValue(GenericHandleManager::GetPartIdx(collectionHandle)))
};
});
}
- 这是应返回的 HandleRange 类型:
/**
* Defines an alias representing a boost range for handles.
*/
using HandleRange = boost::any_range<Handle, boost::forward_traversal_tag, const Handle>;
- 使用的 Handle 对象:
class Handle
{
public:
/**
* Construct a handle from a handle value.
* @param value The handle's value.
*/
inline explicit Handle(int_fast64_t value) noexcept : _value(value)
{
}
...
}
感谢您的任何建议!
答:
1赞
sehe
12/11/2020
#1
不知何故,这有效,但这并不干净
这不应该在没有诊断的情况下编译,如 .auto
std::initializer_list<Handle>
该方法调用 Undefined Behavior,因为初始值设定项列表在返回后不存在。
解决 方案
应该能够返回迭代器范围。any_range
指针是迭代器。
任何一个对象都可以看作是一个范围。这是一个有效的迭代器范围。o
[&o, &o + 1)
如果返回引用,则将它们组合在一起已经是一个解决方案:GenericHandleManager::CreatePartHandleValue(...)
const HandleRange BasicCollection::GetPartHandles() const {
Handle& h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return boost::make_iterator_range(&h, &h + 1));
}
单例范围
但是,如果它返回一个临时值,则需要将其设置为“范围”:
template <typename T>
struct SingletonRange : boost::iterator_range<T*> {
T val;
SingletonRange(T val)
: boost::iterator_range<T*>(std::addressof(val), std::addressof(val) + 1),
val(std::move(val))
{ }
};
现在,您可以安全地¹写入(即使返回一个临时的):CreatePartHandleValue
HandleRange BasicCollection::GetPartHandles() const {
Handle h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return SingletonRange<Handle> {h};
}
完整演示
#include <boost/range/iterator_range.hpp>
template <typename T>
struct SingletonRange : boost::iterator_range<T*> {
T val;
SingletonRange(T val)
: boost::iterator_range<T*>(std::addressof(val), std::addressof(val) + 1),
val(std::move(val))
{ }
};
struct Handle{};
struct GenericHandleManager {
static int GetPartIdx(Handle) { return 42; }
static Handle CreatePartHandleValue(int) { return {}; }
};
#include <boost/range/any_range.hpp>
using HandleRange = boost::any_range<Handle, boost::forward_traversal_tag, const Handle>;
struct BasicCollection {
HandleRange GetPartHandles() const;
private:
Handle _collectionHandle;
};
HandleRange BasicCollection::GetPartHandles() const {
Handle h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return SingletonRange<Handle> {h};
}
#include <iostream>
int main() {
BasicCollection coll;
for (Handle h : coll.GetPartHandles()) {
std::cout << "Handle in loop\n";
boost::ignore_unused_variable_warning(h);
}
}
请记住,复制该范围与复制一个加复制本身一样昂贵。我是 假设 Handle 是轻量级的(与手柄一样)
iterator_range<Handle*>
Handle
指纹
Handle in loop
¹ 只要确保在范围生存期结束后不使用 SingletonRange 中的任何迭代器即可。不过,这是一种常见的 C++ 模式
评论