为什么在迭代时不能使用模板

时间:2020-12-27 22:46:30

When compiling :

编译时:

#include <vector>

template<class T> class foo {

    void bar() {
        std::vector<T> x;
        std::vector<T>::iterator i = x.begin();

    }
};


int main() {
    return 0;
}

I get :

我明白了:

# g++ ~test.cpp
test.cpp: In member function `void foo<T>::bar()':
test.cpp:7: error: expected `;' before "i"

Shouldn't this work?

这不应该工作吗?

g++ version 3.4.3 on RHEL.

RHEL上的g ++版本3.4.3。

3 个解决方案

#1


You can, but you need to tell it that iterator there is a type (it doesn't know, because in general it can depend on T - as vector is a template type, and could in theory have specializations for some T where iterator is a function or something else). So, you have to use typename to indicate that it is always a type:

你可以,但你需要告诉它迭代器有一个类型(它不知道,因为一般来说它可以依赖于T - 因为vector是一个模板类型,并且理论上可以对某些T具有特化,其中迭代器是功能或其他)。因此,您必须使用typename来指示它始终是一个类型:

typename std::vector<T>::iterator i = x.begin();

#2


This should do:

这应该做:

template<class T> class foo {

    void bar() {
        std::vector<T> x;
        typename std::vector<T>::iterator i = x.begin();

    }
};

I'll quote the IBM C++ compiler manual:

我将引用IBM C ++编译器手册:

The typename keyword (C++ only) Use the keyword typename if you have a qualified name that refers to a type and depends on a template parameter. Only use the keyword typename in template declarations and definitions. The following example illustrates the use of the keyword typename:

typename关键字(仅限C ++)如果您具有引用类型且取决于模板参数的限定名称,请使用关键字typename。仅在模板声明和定义中使用关键字typename。以下示例说明了关键字typename的用法:

template<class T> class A
{
  T::x(y);
  typedef char C;
  A::C d;
}

The statement T::x(y) is ambiguous. It could be a call to function x() with a nonlocal argument y, or it could be a declaration of variable y with type T::x. C++ will interpret this statement as a function call. In order for the compiler to interpret this statement as a declaration, you would add the keyword typename to the beginning of it. The statement A::C d; is ill-formed. The class A also refers to A and thus depends on a template parameter. You must add the keyword typename to the beginning of this declaration:

语句T :: x(y)是不明确的。它可以是使用非局部参数y调用函数x(),也可以是类型为T :: x的变量y的声明。 C ++会将此语句解释为函数调用。为了使编译器将此语句解释为声明,您可以将关键字typename添加到其开头。声明A :: C d;是不正确的。 A类也指A,因此取决于模板参数。您必须将关键字typename添加到此声明的开头:

typename A::C d; You can also use the keyword typename in place of the keyword class in template parameter declarations.

typename A :: C d;您还可以在模板参数声明中使用关键字typename代替关键字class。

#3


In case it isn't clear what the others mean by the compiler not knowing that it's a type: at the point where the compiler parses template foo, it doesn't know that you won't later do:

如果编译器不知道它是一个类型还不清楚其他人是什么意思:在编译器解析模板foo时,它不知道你以后不会这样做:

namespace std {
    template<>
    class vector<int> {
        int iterator(void);
    };
}

And then instantiate foo<int>. Then vector<T>::iterator would be a function, not a type, and the relevant line in foo should fail to parse. To work without help, compilers would have to hold off parsing foo until it's instantiated, and they've found the right class to determine whether 'iterator' is a type expression or a value expression. I suspect this could lead to circular dependencies, but would certainly be especially painful to implement. So the standard says that an expression in a template which is dependent on a parameter is assumed not to be a type unless stated to be. There are two (I think) ways to state it to be a type, which are (1) use it as a base class, and (2) qualify it with typename.

然后实例化foo 。然后vector :: iterator将是一个函数,而不是一个类型,并且foo中的相关行应该无法解析。为了在没有帮助的情况下工作,编译器必须暂缓解析foo直到它被实例化,并且他们找到了正确的类来确定'iterator'是类型表达式还是值表达式。我怀疑这可能导致循环依赖,但实施起来肯定会特别痛苦。因此,标准规定,除非声明,否则假定模板中依赖于参数的表达式不是类型。有两种(我认为)方式将它表示为一种类型,它们是(1)将它用作基类,(2)用typename限定它。

OK, so in this example you're actually not allowed to specialize std::vector. And vector actually has more template parameters than just the one I've used. So in your example, the compiler could in theory assume more than it does. But the standard doesn't make special provision for the language to rely on knowledge of what templates are in namespace std, because (1) the intention is that implementations can implement namespace std in normal headers treated the same as any other headers by the compiler, and (2) C++ is supposed to be designed as language+libraries, not as "language with special-case syntax for libraries". In fact, (1) and (2) are sort of the same requirement.

好的,所以在这个例子中你实际上不允许专门化std :: vector。而vector实际上有比我使用的模板参数更多的模板参数。所以在你的例子中,编译器在理论上可以假设比它更多。但是标准并没有特别规定语言依赖于命名空间std中的模板知识,因为(1)意图是实现可以在普通头中实现命名空间std,与编译器的任何其他头一样处理,(2)C ++应该被设计为语言+库,而不是“具有库的特殊语法语言”。实际上,(1)和(2)是相同的要求。

#1


You can, but you need to tell it that iterator there is a type (it doesn't know, because in general it can depend on T - as vector is a template type, and could in theory have specializations for some T where iterator is a function or something else). So, you have to use typename to indicate that it is always a type:

你可以,但你需要告诉它迭代器有一个类型(它不知道,因为一般来说它可以依赖于T - 因为vector是一个模板类型,并且理论上可以对某些T具有特化,其中迭代器是功能或其他)。因此,您必须使用typename来指示它始终是一个类型:

typename std::vector<T>::iterator i = x.begin();

#2


This should do:

这应该做:

template<class T> class foo {

    void bar() {
        std::vector<T> x;
        typename std::vector<T>::iterator i = x.begin();

    }
};

I'll quote the IBM C++ compiler manual:

我将引用IBM C ++编译器手册:

The typename keyword (C++ only) Use the keyword typename if you have a qualified name that refers to a type and depends on a template parameter. Only use the keyword typename in template declarations and definitions. The following example illustrates the use of the keyword typename:

typename关键字(仅限C ++)如果您具有引用类型且取决于模板参数的限定名称,请使用关键字typename。仅在模板声明和定义中使用关键字typename。以下示例说明了关键字typename的用法:

template<class T> class A
{
  T::x(y);
  typedef char C;
  A::C d;
}

The statement T::x(y) is ambiguous. It could be a call to function x() with a nonlocal argument y, or it could be a declaration of variable y with type T::x. C++ will interpret this statement as a function call. In order for the compiler to interpret this statement as a declaration, you would add the keyword typename to the beginning of it. The statement A::C d; is ill-formed. The class A also refers to A and thus depends on a template parameter. You must add the keyword typename to the beginning of this declaration:

语句T :: x(y)是不明确的。它可以是使用非局部参数y调用函数x(),也可以是类型为T :: x的变量y的声明。 C ++会将此语句解释为函数调用。为了使编译器将此语句解释为声明,您可以将关键字typename添加到其开头。声明A :: C d;是不正确的。 A类也指A,因此取决于模板参数。您必须将关键字typename添加到此声明的开头:

typename A::C d; You can also use the keyword typename in place of the keyword class in template parameter declarations.

typename A :: C d;您还可以在模板参数声明中使用关键字typename代替关键字class。

#3


In case it isn't clear what the others mean by the compiler not knowing that it's a type: at the point where the compiler parses template foo, it doesn't know that you won't later do:

如果编译器不知道它是一个类型还不清楚其他人是什么意思:在编译器解析模板foo时,它不知道你以后不会这样做:

namespace std {
    template<>
    class vector<int> {
        int iterator(void);
    };
}

And then instantiate foo<int>. Then vector<T>::iterator would be a function, not a type, and the relevant line in foo should fail to parse. To work without help, compilers would have to hold off parsing foo until it's instantiated, and they've found the right class to determine whether 'iterator' is a type expression or a value expression. I suspect this could lead to circular dependencies, but would certainly be especially painful to implement. So the standard says that an expression in a template which is dependent on a parameter is assumed not to be a type unless stated to be. There are two (I think) ways to state it to be a type, which are (1) use it as a base class, and (2) qualify it with typename.

然后实例化foo 。然后vector :: iterator将是一个函数,而不是一个类型,并且foo中的相关行应该无法解析。为了在没有帮助的情况下工作,编译器必须暂缓解析foo直到它被实例化,并且他们找到了正确的类来确定'iterator'是类型表达式还是值表达式。我怀疑这可能导致循环依赖,但实施起来肯定会特别痛苦。因此,标准规定,除非声明,否则假定模板中依赖于参数的表达式不是类型。有两种(我认为)方式将它表示为一种类型,它们是(1)将它用作基类,(2)用typename限定它。

OK, so in this example you're actually not allowed to specialize std::vector. And vector actually has more template parameters than just the one I've used. So in your example, the compiler could in theory assume more than it does. But the standard doesn't make special provision for the language to rely on knowledge of what templates are in namespace std, because (1) the intention is that implementations can implement namespace std in normal headers treated the same as any other headers by the compiler, and (2) C++ is supposed to be designed as language+libraries, not as "language with special-case syntax for libraries". In fact, (1) and (2) are sort of the same requirement.

好的,所以在这个例子中你实际上不允许专门化std :: vector。而vector实际上有比我使用的模板参数更多的模板参数。所以在你的例子中,编译器在理论上可以假设比它更多。但是标准并没有特别规定语言依赖于命名空间std中的模板知识,因为(1)意图是实现可以在普通头中实现命名空间std,与编译器的任何其他头一样处理,(2)C ++应该被设计为语言+库,而不是“具有库的特殊语法语言”。实际上,(1)和(2)是相同的要求。