问题在于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;
...
};
}
再一次,做作,但是编译器在解析模板时不可能预先知道在您实际实例化具有特定类型的模板之前不会出现这种特化。