Visual Studio编译此代码很好,但gcc只允许它在没有Template运算符的情况下编译.使用Template运算符,它会出现以下错误:
第29行:错误:预期`;' 在"itrValue"之前
class Test { public: Test& operator<<(const char* s) {return *this;} // not implemented yet Test& operator<<(size_t s) {return *this;} // not implemented yet Test& operator<< (const std::list& strList) { *this << "count=" << strList.size() << "("; for (std::list ::const_iterator itrValue = strList.begin(); itrValue != strList.end(); ++itrValue) { *this << " " << *itrValue; } *this << ")"; return *this; } template Test& operator<< (const std::list & listTemplate) { *this << "count=" << listTemplate.size() << "("; // this is line 28, the next line is the offending line for (std::list ::const_iterator itrValue = listTemplate.begin(); itrValue != listTemplate.end(); ++itrValue) { *this << " " << *itrValue; } *this << ")"; return *this; } };
Pieter.. 16
GCC是对的,const_iterator是一个类型,并且模板依赖于模板运算符<<,你需要告诉编译器它是一个类型而不是一个变量:
typename std::list::const_iterator
David Rodríg.. 5
要完成@Pieter答案,这是正确的,有关如何处理模板的更多信息.首先,只有在实例化模板时才会编译模板,因此如果您没有为给定类型实例化模板,那么代码将永远不会被编译.
现在,当您实例化模板时,模板代码有两步验证.首先,无论实例化类型是什么,都验证模板的正确性.要查看一个更简单易懂的示例:
#include "a.h" templatevoid f( T const & ) { T::type x; // is T::type a type? }; int main() { A a; f( a ); }
在第一阶段,检查模板的语法正确性,而不考虑A确实是什么.此时,语法A :: type可以是名称为"type"的类型,也可以是同名的静态变量.
struct A { // version 1 typedef int type; }; struct A { // version 2 static std::string type; }; std::string A::type = "A";
在第一种情况下,type确实是一种类型,而第二种情况则不是.现在标准规定,如果它实际上是一个类型,那么模板的程序员必须声明,以便通过上面的语法通知编译器:
templatevoid f( T const & a ) { typename T::type x; // define a variable x of type T::type }
现在,为了完成处理,编译器必须检查模板代码本身不仅是正确的,而且当它用特定类型T实例化时它也是正确的.这是编译器在第二阶段验证期间执行的操作.它应用类型和重新检查错误.
在你的情况下,它有点争议,因为每个人(但编译器)都知道std :: list :: const_iterator是任何给定T的类型.嗯,它不需要.从语言的角度来看,一些代码可以为特定数据类型T提供与一般列表模板不同的模板特化.编译器无法知道是否可以这样.
请注意,在std命名空间中使用与重新定义迭代器类型一样改变行为的东西来专门化模板是非常错误的.但编译器将std命名空间视为任何其他命名空间,并列出任何其他模板化类.
GCC是对的,const_iterator是一个类型,并且模板依赖于模板运算符<<,你需要告诉编译器它是一个类型而不是一个变量:
typename std::list::const_iterator
要完成@Pieter答案,这是正确的,有关如何处理模板的更多信息.首先,只有在实例化模板时才会编译模板,因此如果您没有为给定类型实例化模板,那么代码将永远不会被编译.
现在,当您实例化模板时,模板代码有两步验证.首先,无论实例化类型是什么,都验证模板的正确性.要查看一个更简单易懂的示例:
#include "a.h" templatevoid f( T const & ) { T::type x; // is T::type a type? }; int main() { A a; f( a ); }
在第一阶段,检查模板的语法正确性,而不考虑A确实是什么.此时,语法A :: type可以是名称为"type"的类型,也可以是同名的静态变量.
struct A { // version 1 typedef int type; }; struct A { // version 2 static std::string type; }; std::string A::type = "A";
在第一种情况下,type确实是一种类型,而第二种情况则不是.现在标准规定,如果它实际上是一个类型,那么模板的程序员必须声明,以便通过上面的语法通知编译器:
templatevoid f( T const & a ) { typename T::type x; // define a variable x of type T::type }
现在,为了完成处理,编译器必须检查模板代码本身不仅是正确的,而且当它用特定类型T实例化时它也是正确的.这是编译器在第二阶段验证期间执行的操作.它应用类型和重新检查错误.
在你的情况下,它有点争议,因为每个人(但编译器)都知道std :: list :: const_iterator是任何给定T的类型.嗯,它不需要.从语言的角度来看,一些代码可以为特定数据类型T提供与一般列表模板不同的模板特化.编译器无法知道是否可以这样.
请注意,在std命名空间中使用与重新定义迭代器类型一样改变行为的东西来专门化模板是非常错误的.但编译器将std命名空间视为任何其他命名空间,并列出任何其他模板化类.