How to properly deduce a dereferenced type of the iterator returned from std::set::begin()?

时间:2018-12-03 13:05:27

标签: c++

I have a template class with container type defined as a StorageType template.

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

This works for the most of the stl containers. But when it comes to std::set I am facing an issue because mStorage.begin() returns const_iterator and aFnc( *it ) compilation fails as aFnc function expects StorageType::value_type& which is non-const.

I have tried to deduce a proper type by getting the result of std::set::begin and deducing the dereferenced type of the iterator received by that, that was looking like:

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

But seems that std::iterator_traits<>::value_type returns non-const value type regardless the fact that real iterator from std::set::begin() dereferences to const T&.

My goal is to deduce a proper signature of the function provided as an argument. Everything will compile for std::set if I will define mentioned function as ( const std::function& aFnc ), but will not work for other container types like vector.

2 个答案:

答案 0 :(得分:2)

std::set doesn't allow to modify the elements via iterators. Both std::set::iterator and std::set::const_iterator are constant iterators (may even be the same type). This is because std::set must be not allow duplicates.

So no matter what type deduction witchery it is simply not possible to modify elements of the set in this kind of for iteration. If aFnc needs to modify elements you can't use std::set.

If instead aFnc doesn't modify its arguments then you need to make the arg const:

using StoredType = typename StorageType::value_type;

void iterate(const std::function<bool(const StoredType&)>& aFnc)

答案 1 :(得分: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) );
}