为什么编译器对此模板存在范围问题?

时间:2016-04-11 13:06:04

标签: c++ templates vector scope iterator

我发现自己经常从vector删除元素,而不关心维护顺序,这意味着使用erase-remove会浪费。最好将要移除的元素与最后一个元素交换pop_back()。标准库中似乎没有任何东西可以做到这一点,所以我正在尝试编写自己的模板,但我真的没有掌握模板语法。

我写了这个:

template<typename T>
void unordered_erase(std::vector<T>& vec, const std::vector<T>::iterator& it)
{
    if (it != vec.end())
    {
        std::swap(vec.back(), *it);
        vec.pop_back();
    }
}

然而编译器抱怨。

  

error: need ‘typename’ before ‘std::vector<_RealType>::iterator’ because ‘std::vector<_RealType>’ is a dependent scope

所以我改变它并编译。

template<typename T>
void unordered_erase(std::vector<T>& vec, const typename std::vector<T>::iterator& it)
{
    if (it != vec.end())
    {
        std::swap(vec.back(), *it);
        vec.pop_back();
    }
}

我真正不明白的是编译器如何推断std::vector<T>而不是std::vector<T>::iterator

1 个答案:

答案 0 :(得分:4)

编译器能够推导出类型Tstd::vector<_RealType>::iterator未被推断,它是std::vector的嵌入式类型。

需要typename,以便编译器可以从成员变量名中消除嵌入类型名称的歧义。

来自cppreference;

  

在模板的声明或定义(包括别名模板)中,除了关键字{{{}之外,不是当前实例化成员且依赖于模板参数的名称不被视为类型使用1}} 或者除非它已经被建立为类型名称,例如使用typename声明或用于命名基类。

当存在歧义时,名称依赖于模板参数,编译器必须假定名称是成员变量,而不是类型。