GCC模板问题

时间:2008-12-23 19:14:24

标签: c++ templates gcc

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<const char*>& strList)
  {
    *this << "count=" << strList.size() << "(";

    for (std::list<const char*>::const_iterator itrValue = strList.begin();
         itrValue != strList.end(); ++itrValue)
    {
        *this << " " << *itrValue;
    }

    *this << ")";

    return *this;
  }

  template <class T>
  Test& operator<< (const std::list<T>& listTemplate)
  {
    *this << "count=" << listTemplate.size() << "(";

    // this is line 28, the next line is the offending line
    for (std::list<T>::const_iterator itrValue = listTemplate.begin();
         itrValue != listTemplate.end(); ++itrValue)
    {
        *this << " " << *itrValue;
    }

    *this << ")";

    return *this;
  }
};

3 个答案:

答案 0 :(得分:16)

GCC是对的,const_iterator是一个类型,模板依赖于模板运算符&lt;&lt;,你需要告诉编译器它是一个类型而不是一个变量:

typename std::list<T>::const_iterator

答案 1 :(得分:5)

要完成@Pieter的答案,这是正确的,有关如何处理模板的更多信息。 首先,模板仅在实例化时进行编译,因此如果您没有为给定类型实例化模板,那么代码将永远不会被编译。

现在,当您实例化模板时,模板代码有两步验证。首先,无论实例化类型是什么,都验证模板的正确性。要查看一个更简单易懂的示例:

#include "a.h"

template <typename T> void 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确实是一种类型,而第二种情况则不是。现在标准规定,如果它实际上是一个类型,那么模板的程序员必须声明,以便用上面的语法通知编译器:

template <typename T> void 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命名空间看作任何其他命名空间,并列为任何其他模板化类。

答案 2 :(得分:4)

我认为值得告诉你其他消歧。对于typename我已经回答了另一个here

另一个是模板。看这里:

template<typename T>
struct some {
    template<int V>
    struct other {
        typedef int type;
        static const int value = V;
    };
};

template<typename V>
void doit() {
    typename some<V>::template other<42>::type * int_pointer;
}

请注意我们必须使用两个模板和typename消除歧义。 typename告诉编译器

  

您访问的名为::type的内容确实是一种类型。不要做乘法,这会错误地认为::type是静态值(整数或其他)。

模板告诉编译器

  

other<42>是与42参数一起使用的模板。这不是使用operator>的{​​{1}}和operator<other以及后面的内容进行比较(这确实是完全无意义的)。