【问题标题】:How to convert a single object to a boost::any_range?如何将单个对象转换为 boost::any_range?
【发布时间】:2021-03-22 02:06:39
【问题描述】:

我正在尝试创建并返回一个 boost:any_range 仅包含一个对象(我不知道这是否是核心问题),但我收到以下错误:

  • 错误 C2893:无法专门化函数模板 'range_iterator::type boost::range_adl_barrier::begin(T &)'
  • 注意:使用以下模板参数:
  • 注意:'T=const WrappedRange'
  • 错误 C2672:“结束”:找不到匹配的重载函数
  • 错误 C2893:无法专门化函数模板
    'range_iterator::type boost::range_adl_barrier::end(T &)'
  • 注意:使用以下模板参数:注意:'T=const
    WrappedRange'

下面可以找到相关代码sn-ps:

  1. 这是我要调用的函数,但在编译过程中失败:
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)))
        };
    });
}
  1. 这是应返回的 HandleRange 类型:
/**
 * Defines an alias representing a boost range for handles.
 */
 using HandleRange = boost::any_range<Handle, boost::forward_traversal_tag, const Handle>;
  1. 使用的 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)
      {
      }
...
}

感谢您的任何建议!

【问题讨论】:

    标签: c++ boost compiler-errors boost-range boost-iterators


    【解决方案1】:

    不知怎的,这很有效,但那不是很干净

    这不应该在没有诊断的情况下编译,因为auto 被推断为std::initializer_list&lt;Handle&gt;。

    该方法调用Undefined Behaviour,因为初始化列表在返回后不存在。

    解决方案

    any_range 应该能够返回一个迭代器范围。

    指针是迭代器。

    任何单个对象o 都可以看作是一个范围[&amp;o, &amp;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};
    }
    

    完整演示

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

    请记住,复制该范围与复制一个 iterator_range&lt;Handle*&gt; 加上复制 Handle 本身。我是 假设 Handle 是轻量级的(与通常的手柄一样)

    打印

    Handle in loop
    

    ¹ 只要您确保在范围的生命周期后不使用 SingletonRange 中的任何迭代器。这是一个常见的 C++ 模式

    【讨论】:

      猜你喜欢
      • 2022-01-15
      • 2022-01-15
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      • 2022-12-17
      • 2013-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多