C++模板:返回列表::迭代器

发布于 2024-10-31 22:54:22 字数 673 浏览 0 评论 0原文

我怎样才能使下面的代码工作?在编译期间,我收到一条错误消息,告诉我 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)
{
    // ...
}

How can I make the following code work? During compilation I get an error telling me that the searchForResource function has no return type.

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);
};

Also, is this how I would define the searchForResource function?

template<class t>
std::list<typename ResourceManager<T>::ResourceWrapper*>::iterator
    ResourceManager<T>::searchForResource(const std::string& file)
{
    // ...
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

暗喜 2024-11-07 22:54:22

std::list::iterator 编译器很难理解。在实现和声明中添加 typename 前缀,让编译器知道它是一个类型。

就像这样:

typename std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);

std::list<ResourceWrapper*>::iterator is hard for the compiler to understand. Prefix it with typename in both the implementation and the declaration to let the compiler know that it's a type.

Like so:

typename std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);
一直在等你来 2024-11-07 22:54:22
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 ...   
}
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 ...   
}
执手闯天涯 2024-11-07 22:54:22

有一个经验法则可以避免此类编译错误。

每当您声明变量或函数时,使用模板后跟作用域解析运算符::,然后始终将关键字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

同样的事情也适用于函数声明。

There is a rule of thumb to avoid such compilation errors.

Whenever you are declaring a variable or function, with a template followed by scope resolution operator :: then always put a keyword typename in front of the definition.

For example,

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

Same thing is applicable to function declaration also.

何时共饮酒 2024-11-07 22:54:22

我认为您缺少 typename 关键字。

I think you're missing a typename keyword.

無處可尋 2024-11-07 22:54:22

问题是 ResourceWrapper 是一个依赖名称 *(它的定义取决于类型参数 T),这使得 std: :列表< 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 模板的所有可能实例化都有一个定义,现在< code>ResourceWrapper 不再依赖于 T,并且不再需要(也不正确)typename

* 为什么依赖于 ResourceWrapper 以及这对代码有何影响。

通过讨论完全限定名称,可以更容易地看出 ResourceWrapper 依赖于类型 T 的原因:::ResourceManager::ResourceWrapperT 是类型的一部分,因此 T 影响 ResourceWrapper 的实际定义。这在某种程度上是一个人为的示例,您可以说,如果编译器正在解析此特定模板,那么它必须知道 ResourceWrapper 是一种类型,因此 std::liststd::listResourceWrapper*>::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;
...
};
}

同样,这是人为的,但编译器不可能预先知道解析模板,在您实际使用特定类型实例化模板之前,不会出现这种专门化。

The problem is that ResourceWrapper is a dependent name *(it's definition depends on the type argument T), and that makes std::list< ResourceWrapper * > a dependent type name. Templates are checked in two passes, during the first pass, correctness of the template without actual type substitution is checked. Now when you type std::list< ResourceWrapper* >::iterator the compiler cannot know upfront that iterator is in fact a type and not an static attribute or member of the class std::list< ResourceWrapper* > because of the type being dependent and the T not yet being substituted.

You have to hint the compiler as to inform it that the iterator is indeed a type by using the typename keyword, as others have already mentioned before:

typename std::list< ResourceWrapper* >::iterator

Without seeing the rest of the code, I cannot say, but it seems as if ResourceWrapper should actually not be a dependent type on T. If it is in fact non-dependent, you should move the type outside of the class template. in that case, the typename will no longer be required:

struct ResourceWrapper;
template <typename T>
class ResourceManager {
   std::list<ResourceWrapper*>::iterator searchForResource(const std::string& file);
...

Because it is defined outside of the template there is a single definition for all possible instantiations of the ResourceManager template, now ResourceWrapper is no longer dependent on T, and typename is no longer needed (nor correct).

* Why is ResourceWrapper dependent and how could this affect the code.

The reason that ResourceWrapper is dependent on the type T is easier seen by discussing the fully qualified name: ::ResourceManager<T>::ResourceWrapper. The T is part of the type, and as such T affects the actual definition of ResourceWrapper. This is somehow a contrived example in that you can arguably say that if the compiler is parsing this particular template, then it must know that ResourceWrapper is a type, and thus that std::list< ResourceWrapper*>::iterator is a type... and here is the problem. There is no particular reason not to have an specialization of the std::list template for a particular instantiation of ResourceManager:

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;
...
};
}

Again, contrived, but the compiler cannot possibly know upfront while parsing the template that such an specialization will not be present before you actually instantiate the template with a particular type.

如梦 2024-11-07 22:54:22

您有 ResourceWrapper 结构的前向声明,这对于编译良好的行来说已经足够了,但是您收到错误,因为此时编译器需要 ResourceWrapper 结构的完整类型声明。 (可能是你的答案,这段代码实际上可以在 VS2008 上编译得很好)

you have forward declaration of ResourceWrapper struct which is good enough for the line that compiles fine, but you are getting the error because at that point compiler needs full type declaration for ResourceWrapper struct. (possibly your answer, this code actually compiles fine with VS2008)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文