【问题标题】:Error with T::iterator, where template parameter T might be vector<int> or list<int>T::iterator 出错,其中模板参数 T 可能是 vector<int> 或 list<int>
【发布时间】:2011-04-13 16:43:40
【问题描述】:

我正在尝试编写一个函数来打印常见 STL 容器(向量、列表等)的表示。我给函数一个模板参数 T,例如,它可能代表向量。我在获取 T 类型的迭代器时遇到问题。

vector<int> v(10, 0);
repr< vector<int> >(v);

...

template <typename T>
void repr(const T & v)
{
    cout << "[";
    if (!v.empty())
    {
        cout << ' ';
        T::iterator i;
        for (i = v.begin(); 
             i != v.end()-1;
             ++i)
        {
            cout << *i << ", ";
        }
        cout << *(++i) << ' ';
    }
    cout << "]\n";
}

...

brett@brett-laptop:~/Desktop/stl$ g++ -Wall main.cpp
main.cpp: In function ‘void repr(const T&)’:
main.cpp:13: error: expected ‘;’ before ‘i’
main.cpp:14: error: ‘i’ was not declared in this scope
main.cpp: In function ‘void repr(const T&) [with T = std::vector<int, std::allocator<int> >]’:
main.cpp:33:   instantiated from here
main.cpp:13: error: dependent-name ‘T::iterator’ is parsed as a non-type, but instantiation yields a type
main.cpp:13: note: say ‘typename T::iterator’ if a type is meant

我按照编译器的建议尝试了“typename T::iterator”,但只得到了一个更神秘的错误。

编辑:感谢您的帮助!以下是任何想要使用此功能的人的工作版本:

template <typename T>
void repr(const T & v)
{
    cout << "[";
    if (!v.empty())
    {
        cout << ' ';
        typename T::const_iterator i;
        for (i = v.begin(); 
             i != v.end();
             ++i)
        {
            if (i != v.begin())
            {
                cout << ", ";
            }
            cout << *i;
        }
        cout << ' ';
    }
    cout << "]\n";
}

【问题讨论】:

  • 发布“更神秘”的错误信息怎么样?
  • 顺便说一句,您可能希望将 v.end()-1 替换为非随机访问迭代器也支持的其他内容。

标签: c++ templates stl repr


【解决方案1】:

你需要typename 告诉编译器::iterator 应该是一个类型。编译器不知道它是一个类型,因为在实例化模板之前它不知道 T 是什么。例如,它也可以引用一些静态数据成员。这是你的第一个错误。

您的第二个错误是v 是对const 的引用。因此,您必须使用::const_iterator 而不是::iterator。您不能向常量容器询问非常量迭代器。

【讨论】:

  • 并不是编译器不知道::iterator 是什么,而是标准要求它将其解释为非类型,因为它很好地放入了错误消息中:“依赖-name 'T::iterator' 被解析为非类型,但实例化产生类型"
  • @visitor:使用正确的两阶段实现(读作“非 MSVC”),编译器在第一遍中无法知道 iterator 是什么,因为尚未设置模板参数。参见例如项目 6 和 7 here.
【解决方案2】:

T::iterator i; 更改为typename T::const_iterator i;,因为::iteratorT 类型,而vconst &amp;

在限定依赖类型之前,您需要typename。 如果没有typename,则有一条 C++ 解析规则规定,合格的依赖名称应解析为 non-types,即使它会导致语法错误。

typename 声明后面的名称应被视为一种类型。否则,名称将被解释为引用非类型。

【讨论】:

    【解决方案3】:

    也许这会有所帮助:

    Typename 在引用类型的限定依赖名称之前是必需的,除非该名称正在命名基类或在初始化列表中。在模板中使用限定(但不依赖的名称)之前,typename 是可选的,除非在命名基类或初始化列表时再次使用。

    【讨论】:

      猜你喜欢
      • 2017-03-23
      • 2015-08-21
      • 1970-01-01
      • 2011-03-13
      • 2013-02-18
      • 2019-11-29
      • 2011-07-18
      • 1970-01-01
      相关资源
      最近更新 更多