首页 文章

如何正确推导出从std :: set :: begin()返回的解除引用类型的迭代器?

提问于
浏览
2

我有一个模板类,其容器类型定义为StorageType模板 .

StorageType mStorage;
....
void iterate( const std::function<bool( typename StorageType::value_type& )>& aFnc )
{
    for( auto it = mStorage.begin(); it != mStorage.end(); ++it )
    {
        aFnc( *it );
    }
}

这适用于大多数stl容器 . 但是当谈到std :: set时我遇到了一个问题,因为mStorage.begin()返回const_iterator并且aFnc(* it)编译失败,因为aFnc函数需要StorageType :: value_type&non-const .

我试图通过获取std :: set :: begin的结果并推导出由它接收的迭代器的解引用类型来推断出一个正确的类型,它看起来像:

void iterate( std::function<void(typename std::iterator_traits<std::result_of<decltype(&std::set<ValueType>::begin)(std::set<ValueType>)>::type>::value_type& )>& aFnc )

但似乎std :: iterator_traits <> :: value_type返回非const值类型,而不管std :: set :: begin()中的实数迭代器是否取消引用const T& .

我的目标是推断出作为参数提供的函数的正确签名 . 如果我将所提到的函数定义为(const std :: function&aFnc),那么将为std :: set编译所有内容,但不适用于其他容器类型,如vector .

2 回答

  • 1

    你这里不需要 std::function . 让 aFnc 成为推导出的模板参数 .

    template <typename Func>
    void iterate( Func aFnc )
    {
        for( auto & obj : mStorage )
        {
            aFnc( obj );
        }
    }
    

    要么

    template <typename Func>
    void iterate( Func && aFnc )
    {
        std::for_each( mStorage.begin(), mStorage.end(), std::forward<Func>(aFnc) );
    }
    
  • 2

    std::set 不允许通过迭代器修改元素 . std::set::iteratorstd::set::const_iterator 都是常量迭代器(甚至可以是相同的类型) . 这是因为 std::set 必须不允许重复 .

    所以无论什么类型的演绎巫术都不可能在这种迭代中修改 set 的元素 . 如果 aFnc 需要修改元素,则无法使用 std::set .

    如果相反 aFnc 不修改其参数,那么你需要使arg const:

    using StoredType = typename StorageType::value_type;
    
    void iterate(const std::function<bool(const StoredType&)>& aFnc)
    

相关问题