如何将单个对象转换为boost :: any_range? [英] How to convert a single object to a boost::any_range?

查看:58
本文介绍了如何将单个对象转换为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'

下面您可以找到相关的代码段:

  1. 这是我要调用的函数,并且在编译过程中失败:

  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)))};});} 

  1. 应返回的HandleRange类型:

 /***定义一个别名,表示手柄的提升范围.*/使用HandleRange = boost :: any_range< Handle,boost :: forward_traversal_tag,const Handle>; 

  1. 使用的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};} 

完整演示

在Coliru上直播

  #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:

  1. 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)))
        };
    });
}

  1. 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>;

  1. 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

Live On Coliru

#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)

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆