2

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

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

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

  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)
      {
      }
...
}

感谢您的任何建议!

4

1 回答 1

1

不知何故,这可行,但这并不是很干净

这不应该在没有诊断的情况下编译,正如auto推断为std::initializer_list<Handle>.

该方法调用未定义行为,因为初始化列表在返回后不存在。

解决方案

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

请记住,复制该范围与复制一个 iterator_range<Handle*>加号复制Handle自身一样昂贵。我假设把手是轻量级的(就像把手一样)

印刷

Handle in loop

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

于 2020-12-10T16:44:29.353 回答