如何将单个对象转换为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{返回HandleRange//返回->也尝试了这个{Handle(GenericHandleManager :: CreatePartHandleValue(GenericHandleManager :: GetPartIdx(_collectionHandle)))};}
某种程度上可行,但这并不是很干净:
const HandleRange BasicCollection :: GetPartHandles()const{自动容器= {_collectionHandle};返回容器|boost :: adaptors :: transformed([collectionHandle = _collectionHandle](const auto& index_value){返回HandleRange :: value_type{Handle(GenericHandleManager :: CreatePartHandleValue(GenericHandleManager :: GetPartIdx(collectionHandle)))};});}
- 应返回的HandleRange类型:
/***定义一个别名,表示手柄的提升范围.*/使用HandleRange = boost :: any_range< Handle,boost :: forward_traversal_tag,const Handle>;
- 使用的Handle对象:
class句柄{上市:/***从句柄值构造一个句柄.* @param value句柄的值.*/内联显式Handle(int_fast64_t value)noexcept:_value(value){}...}
谢谢您的建议!
某种程度上可行,但这并不是很干净
在没有诊断的情况下不应该编译,因为 auto
推断为 std :: initializer_list< Handle>
.
该方法调用未定义的行为,因为返回后初始化列表不存在./p>
解决方案
any_range
应该能够返回迭代器范围.
指针是迭代器.
任何单个对象 o
都可以视为范围 [& o,& o + 1)
.这是有效的迭代器范围.
将这些组合起来已经是解决方案,如果 GenericHandleManager :: CreatePartHandleValue(...)
返回引用:
const HandleRange BasicCollection :: GetPartHandles()const {处理和h =GenericHandleManager :: CreatePartHandleValue(GenericHandleManager :: GetPartIdx(_collectionHandle));返回boost :: make_iterator_range(& h,& h +1));}
单一范围
但是,如果它返回一个临时值,则需要将其设为范围":
模板< 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 {句柄h =GenericHandleManager :: CreatePartHandleValue(GenericHandleManager :: GetPartIdx(_collectionHandle));返回SingletonRange< Handle>{H};}
完整演示
#include< boost/range/iterator_range.hpp>模板< 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 {静态诠释GetPartIdx(Handle){return 42;}静态处理CreatePartHandleValue(int){return {};}};#include< boost/range/any_range.hpp>使用HandleRange = boost :: any_range< Handle,boost :: forward_traversal_tag,const Handle>;struct BasicCollection {HandleRange GetPartHandles()const;私人的:处理_collectionHandle;};HandleRange BasicCollection :: GetPartHandles()const {句柄h =GenericHandleManager :: CreatePartHandleValue(GenericHandleManager :: GetPartIdx(_collectionHandle));返回SingletonRange< Handle>{H};}#include< iostream>int main(){BasicCollection coll;对于(句柄h:coll.GetPartHandles()){std :: cout<<在循环中处理\ n";boost :: ignore_unused_variable_warning(h);}}
请记住,复制该范围与复制
iterator_range< Handle *>
以及复制Handle
本身.我是假设手柄是轻型的(手柄通常如此)
打印
处理循环
¹,只要您确定在该范围的生命周期内不使用SingletonRange中的任何迭代器即可.虽然这是一种常见的C ++模式
I'm trying to create and return a boost:any_range that contains only one object (I don't know if that's the core problem) but I get the following errors:
- error C2893: Failed to specialize function template 'range_iterator<C,void>::type boost::range_adl_barrier::begin(T &)'
- note: With the following template arguments:
- note: 'T=const WrappedRange'
- error C2672: 'end': no matching overloaded function found
- error C2893: Failed to specialize function template
'range_iterator<C,void>::type boost::range_adl_barrier::end(T &)' - note: With the following template arguments: note: 'T=const
WrappedRange'
Below you can find the relevant code snippets:
- That's the function I want to call and which fails during compiling:
const HandleRange BasicCollection::GetPartHandles() const
{
return HandleRange
//return -> also tried this
{
Handle(GenericHandleManager::CreatePartHandleValue(GenericHandleManager::GetPartIdx(_collectionHandle)))
};
}
Somehow this works, but that's not really clean:
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)))
};
});
}
- That's the HandleRange type that shall be returned:
/**
* Defines an alias representing a boost range for handles.
*/
using HandleRange = boost::any_range<Handle, boost::forward_traversal_tag, const Handle>;
- The used Handle object:
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)
{
}
...
}
Thanks for any suggestions!
Somehow this works, but that's not really clean
That should not compile without diagnostics, as auto
is deduced as std::initializer_list<Handle>
.
That approach invokes Undefined Behaviour because the initializer list doesn't exist after returning.
Solutions
The any_range
should be able to return an iterator range.
Pointers are iterators.
Any single object o
can be seen as a range [&o, &o + 1)
. That's a valid iterator range.
Combining these would already be a solution if GenericHandleManager::CreatePartHandleValue(...)
returns a reference:
const HandleRange BasicCollection::GetPartHandles() const {
Handle& h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return boost::make_iterator_range(&h, &h + 1));
}
Singleton Ranges
If it returns a temporary, though, you'll need to make that "a range":
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))
{ }
};
Now you can safely¹ write (even though CreatePartHandleValue
returns a temporary):
HandleRange BasicCollection::GetPartHandles() const {
Handle h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return SingletonRange<Handle> {h};
}
Full Demo
#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);
}
}
Keep in mind that copying that range is as expensive as copying an
iterator_range<Handle*>
plus copying theHandle
itself. I'm assuming the Handle is lightweight (as usual for handles)
Prints
Handle in loop
¹ as long as you make sure you don't use any iterators from the SingletonRange after the lifetime of the range. This is a common C++ pattern though
这篇关于如何将单个对象转换为boost :: any_range?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!