为什么编译器对此模板存在作用域问题

Why does the compiler have scoping issues with this template?

本文关键字:存在 作用域 问题 编译器 为什么      更新时间:2023-10-16

我发现自己经常从vector中删除元素,而不关心顺序的维护,这意味着使用擦除删除将是浪费。最好将要移除的元素与最后一个元素和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

编译器能够推导出类型Tstd::vector<_RealType>::iterator没有被推导出来,它是std::vector的一种嵌入类型。

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

来自cppreference;

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

当可能存在歧义时,名称依赖于模板参数,编译器需要假设名称是成员变量的名称,而不是类型的名称。