返回list::迭代器
C++ templates: Returning list::iterator
如何使下面的代码工作?在编译过程中,我得到一个错误,告诉我searchForResource
函数没有返回类型。
template<class T>
class ResourceManager
{
private:
struct ResourceWrapper;
std::list<ResourceWrapper*> resources_; // This compiles fine
std::list<ResourceWrapper*>::iterator // Error occurs here
searchForResource(const std::string& file);
};
另外,这是我如何定义searchForResource
函数吗?
template<class t>
std::list<typename ResourceManager<T>::ResourceWrapper*>::iterator
ResourceManager<T>::searchForResource(const std::string& file)
{
// ...
}
std::list<ResourceWrapper*>::iterator
是编译器很难理解的。在实现和声明中加上 typename
前缀,让编译器知道它是一个类型。
一样:
typename std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);
template<class T>
class ResourceManager
{
private:
struct ResourceWrapper;
std::list<ResourceWrapper*> resources_;
// | typename lost here
// V
typename std::list<ResourceWrapper*>::iterator
searchForResource(const std::string& file);
};
template<class T>
// | typename lost here asterisk lost here |
// V V
typename std::list<typename ResourceManager<T>::ResourceWrapper*>::iterator
ResourceManager<T>::searchForResource(const std::string& file)
{
return ...
}
有一条经验法则可以避免这种编译错误。
每当声明变量或函数时,模板后面跟着作用域解析操作符::
,则始终在定义前放置关键字typename
。
MyNameSpace::MyClass<T> x; // Ok; because template is NOT followed by scope resolution
MyNameSpace::MyClass<T>::MyType x; // Error; MyType can be a variable or a type; so put typename ahead
同样的事情也适用于函数声明
我想你漏掉了一个typename
关键字。
问题是ResourceWrapper
是一个依赖名称*(它的定义取决于类型参数T
),这使得std::list< ResourceWrapper * >
成为一个依赖类型名称。模板分两次检查,在第一次检查中,检查没有实际类型替换的模板的正确性。现在,当您输入std::list< ResourceWrapper* >::iterator
时,编译器无法预先知道iterator
实际上是一个类型,而不是静态属性或类std::list< ResourceWrapper* >
的成员,因为类型是依赖的,而T
还没有被替换。
您必须通过使用typename
关键字提示编译器通知它iterator
确实是一种类型,正如其他人之前已经提到的那样:
typename std::list< ResourceWrapper* >::iterator
没有看到剩下的代码,我不能说,但似乎ResourceWrapper
实际上不应该是T
的依赖类型。如果它实际上是非依赖的,则应该将类型移到类模板之外。在这种情况下,将不再需要typename
:
struct ResourceWrapper;
template <typename T>
class ResourceManager {
std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);
...
因为它是在模板之外定义的,所以ResourceManager
模板的所有可能的实例化都是一个定义,现在ResourceWrapper
不再依赖于T
,并且typename
不再需要(也不正确)。
*为什么ResourceWrapper
是依赖的,这将如何影响代码。
ResourceWrapper
依赖于类型T
的原因通过讨论完全限定名::ResourceManager<T>::ResourceWrapper
可以更容易地看出。T
是类型的一部分,因此T
影响ResourceWrapper
的实际定义。这在某种程度上是一个人为的例子,你可以说,如果编译器正在解析这个特定的模板,那么它必须知道ResourceWrapper
是一个类型,因此std::list< ResourceWrapper*>::iterator
是一个类型……问题来了。没有特别的理由不为ResourceManager
的特定实例化对std::list
模板进行专门化:
namespace std { // you should in general not add things to the std namespace!
// but the implementation can
template <>
struct list< ResourceManager<int>::ResourceWrapper > {
static const int iterator = 5;
...
};
}
同样是人为的,但是编译器在解析模板时不可能预先知道,在您实际使用特定类型实例化模板之前,这种专门化不会出现。
您有ResourceWrapper结构的前向声明,这对于编译好的行来说足够好,但是您正在获得错误,因为在那一点上编译器需要ResourceWrapper结构的完整类型声明。(可能你的答案,这段代码实际上编译良好VS2008)
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- std::list 中的迭代器感知对象
- 当通知迭代器参数初始化为空列表的开头时,list::insert 行为是什么?
- 如何使用 std::list 模板的迭代器擦除
- 如果我在下面的代码中使用 list 而不是 vector,为什么在我尝试在迭代器之间执行减法的行中编译失败?
- 使用迭代器对 std::list 进行排序
- 如何从该列表的元素中获取 std::list<T>::迭代器?
- 为什么 std::list 迭代器没有运算符+
- std::list.end() 不返回"past-the-end"迭代器
- 我可以在 std::list 中移动元素而不会使迭代器或引用无效,但是如何移动呢?
- std::list 中的 rbegin() 永远不会等于指向列表的迭代器?
- 在迭代器时从 std::list 中删除条目
- C++ "argument list for class template "迭代器" is missing"错误
- 无法将 std::set 中的元素迭代器插入到 std::list
- 获取迭代器在基类型 "intrusive doubly linked list" 的指针字典中的位置
- 迭代器的偏移位置为 std::list
- Vector::<int>迭代器与 list::<int>itrator 键在 std::map
- 如何返回迭代器--list:<T>:迭代器,作为函数返回值