如何将单个对象转换为 boost::any_range?
How to convert a single object to a boost::any_range?
我正在尝试创建 return 一个只包含一个对象的 boost:any_range(我不知道这是否是核心问题)但我收到以下错误:
- error C2893: 函数模板特化失败
'range_iterator<C,void>::type boost::range_adl_barrier::begin(T &)'
- 注意:使用以下模板参数:
- 注:'T=const WrappedRange'
- error C2672: 'end': 未找到匹配的重载函数
- error C2893: 函数模板特化失败
'range_iterator<C,void>::type boost::range_adl_barrier::end(T &)'
- 注意:使用以下模板参数:注意:'T=const
包裹范围'
您可以在下面找到相关的代码片段:
- 这就是我要调用的函数,但在编译过程中失败了:
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)))
};
});
}
- 这是应该 returned 的 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)
{
}
...
}
感谢任何建议!
Somehow this works, but that's not really clean
如果没有诊断就不能编译,因为 auto
被推断为 std::initializer_list<Handle>
。
该方法调用 Undefined Behaviour 因为初始化列表在 returning 之后不存在。
解决方案
any_range
应该可以 return 一个迭代器范围。
指针是迭代器。
任何单个对象o
都可以看作是一个范围[&o, &o + 1)
。这是一个有效的迭代器范围。
结合这些已经是一个解决方案如果 GenericHandleManager::CreatePartHandleValue(...)
return参考:
const HandleRange BasicCollection::GetPartHandles() const {
Handle& h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return boost::make_iterator_range(&h, &h + 1));
}
单例范围
如果它 return 是临时的,那么您需要将其设置为“一个范围”:
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
return 是临时的):
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);
}
}
Keep in mind that copying that range is as expensive as copying an
iterator_range<Handle*>
plus copying the Handle
itself. I'm
assuming the Handle is lightweight (as usual for handles)
版画
Handle in loop
¹ 只要您确保在范围的生命周期之后不使用 SingletonRange 中的任何迭代器。这是一个常见的 C++ 模式
我正在尝试创建 return 一个只包含一个对象的 boost:any_range(我不知道这是否是核心问题)但我收到以下错误:
- error C2893: 函数模板特化失败 'range_iterator<C,void>::type boost::range_adl_barrier::begin(T &)'
- 注意:使用以下模板参数:
- 注:'T=const WrappedRange'
- error C2672: 'end': 未找到匹配的重载函数
- error C2893: 函数模板特化失败
'range_iterator<C,void>::type boost::range_adl_barrier::end(T &)' - 注意:使用以下模板参数:注意:'T=const
包裹范围'
您可以在下面找到相关的代码片段:
- 这就是我要调用的函数,但在编译过程中失败了:
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)))
};
});
}
- 这是应该 returned 的 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)
{
}
...
}
感谢任何建议!
Somehow this works, but that's not really clean
如果没有诊断就不能编译,因为 auto
被推断为 std::initializer_list<Handle>
。
该方法调用 Undefined Behaviour 因为初始化列表在 returning 之后不存在。
解决方案
any_range
应该可以 return 一个迭代器范围。
指针是迭代器。
任何单个对象o
都可以看作是一个范围[&o, &o + 1)
。这是一个有效的迭代器范围。
结合这些已经是一个解决方案如果 GenericHandleManager::CreatePartHandleValue(...)
return参考:
const HandleRange BasicCollection::GetPartHandles() const {
Handle& h =
GenericHandleManager::CreatePartHandleValue(
GenericHandleManager::GetPartIdx(_collectionHandle));
return boost::make_iterator_range(&h, &h + 1));
}
单例范围
如果它 return 是临时的,那么您需要将其设置为“一个范围”:
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
return 是临时的):
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);
}
}
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)
版画
Handle in loop
¹ 只要您确保在范围的生命周期之后不使用 SingletonRange 中的任何迭代器。这是一个常见的 C++ 模式