Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何正确推断从std::set::begin()返回的迭代器的解引用类型?_C++ - Fatal编程技术网

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

C++ 如何正确推断从std::set::begin()返回的迭代器的解引用类型?,c++,C++,我有一个模板类,其容器类型定义为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 );

我有一个模板类,其容器类型定义为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 );
    }
}
StorageType-mStorage;
....
void iterate(const std::function和aFnc)
{
for(auto it=mStorage.begin();it!=mStorage.end();++it)
{
aFnc(*it);
}
}
这适用于大多数stl容器。但说到std::set,我面临一个问题,因为mStorage.begin()返回常量迭代器,而aFnc(*it)编译失败,因为aFnc函数需要StorageType::value\u type&这是非常量

我试图通过得到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 )
void迭代(std::function&aFnc)
但似乎std::iterator\u traits::value\u type返回非常量值类型,而不管std::set::begin()中的实际迭代器是否取消对常量T的引用


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

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

所以,无论是哪种类型的演绎,都不可能在这种迭代中修改
集合
的元素。如果
aFnc
需要修改元素,则不能使用
std::set

如果aFnc不修改其参数,则需要使arg常量:

using StoredType = typename StorageType::value_type;

void iterate(const std::function<bool(const StoredType&)>& aFnc)
使用StoredType=typename StorageType::value\u type;
void iterate(const std::function和aFnc)

这里不需要
std::function
。只需将
aFnc
作为推导的模板参数

template <typename Func>
void iterate( Func aFnc )
{
    for( auto & obj : mStorage )
    {
        aFnc( obj );
    }
}
模板
无效迭代(Func aFnc)
{
用于(自动和车载:mStorage)
{
aFnc(obj);
}
}

模板
无效迭代(Func&&aFnc)
{
std::for_each(mStorage.begin()、mStorage.end()、std::forward(aFnc));
}

存储类型的定义是什么?
std::set
不允许修改其元素。从C++17开始,您可以使用
extract
member函数,但这是一种不同的方法,与您发布的方法不匹配。在任何情况下,您希望何时交替注入
std::vector
std::set
?我看不出一个合理的用例,它们是完全不同的容器。@MatthieuBrucher这是一个模板参数。事实上,应该是常量&,而不仅仅是&…@lubgr。我知道它不允许修改。我的目标是推导作为参数提供的函数的正确签名。如果我将set定义为(const std::function&aFnc),那么所有的东西都将为set编译,但对于其他容器类型(如vector)则不起作用。这确实是一个解决方案。我已经在很多地方使用了这个函数,如果我要引入一个模板参数,我将不得不更改上百个地方。@t不,您不需要更改调用位置。可以推导函数模板参数。我是否应该将函数调用从iterate(aFnc)更改为iterate(aFnc)以进行编译?我想是的。不,你不需要
iterate(aFnc)
在该上下文中的意思与
iterate(aFnc)
相同。您完全正确。这是我可以接受的解决方案。出于某种原因,我将不得不指定一个模板括号。
template <typename Func>
void iterate( Func && aFnc )
{
    std::for_each( mStorage.begin(), mStorage.end(), std::forward<Func>(aFnc) );
}