【问题标题】:There are no arguments that depend on a template parameter没有依赖于模板参数的参数
【发布时间】:2012-04-14 01:55:42
【问题描述】:

我正在尝试执行以下操作:

template <class T>
std::ifstream& operator>> (std::ifstream& fin, List<T> l)
{
    T temp;
    l.resize(0);
    fin >> ignore(1,'\t');
    for(ListIterator<T> i=l.begin();i!=l.end();i++)
    {
        fin >> ignore(1,'\t') >> temp;
        l.push_back(temp);
    }
    return fin;
}

我必须从文件中读取所有内容。每个字段由'\t' 字符分隔,所以我必须忽略'\t' 字符。

错误日志如下:

/home/ramy/Documents/C++/Prova/Util.h||In function ‘std::ifstream& Util::operator>> (std::ifstream&, Util::List<T>)’:|
/home/ramy/Documents/C++/Prova/Util.h|431|error: there are no arguments to ‘ignore’ that  depend on a template parameter, so a declaration of ‘ignore’ must be available|
/home/ramy/Documents/C++/Prova/Util.h|431|note: (if you use ‘-fpermissive’, G++ will  accept your code, but allowing the use of an undeclared name is deprecated)|
||=== Build finished: 1 errors, 0 warnings ===|

【问题讨论】:

  • 最好复制+粘贴错误信息进行搜索,即标题中有错字:tamplate

标签: c++ templates


【解决方案1】:

对于内置类型,不执行argument dependent lookup (ADL),因此必须将ignore 符号“导入”到当前命名空间中。

例如,您可以这样做;从最喜欢到最不喜欢(即最具侵入性和名称污染):

  • foobar::ignore (...)
  • using foobar::ignore; ignore(...);
  • using namespace foobar; ignore(...);

错误消息是这样出现的,因为在模板中,您还输入了依赖名称和Two Phase Lookup 的领域。依赖于模板参数的名称,例如

template <typename T> void foo() {
    T x;
    x.frobnicate();
}

在第 2 阶段查找,即在实例化时。不依赖于模板参数的名称,例如

class Foo {};

template <typename T> void foo() {
    Foo foo;
    foo.frobnicate();
}

在第一阶段必须是可解决的。

这种分离有助于模板作者更早地发现错误并找到正确的符号,并且有助于使模板更加通用。例如,在 C# 泛型中,一切都必须是可解析的,这对它们的灵活性提出了相当严格的限制(因为 可能 被泛型 使用的所有东西都必须定义)。相反,一些旧的 C++ 编译器仅在第 2 阶段解决,即在实例化时,这对查找和错误发现产生了一些微妙的后果。

C++ 2 阶段模型结合了 Eager 模型 (C#) 和惰性模型(一些旧的 C++ 编译器)的优点。

【讨论】:

    【解决方案2】:

    如需更简单的答案,请参阅 https://web.archive.org/web/20130423054841/http://www.agapow.net/programming/cpp/no-arguments-that-depend-on-a-template-parameter

    TL;DR:用 this->ignore() 替换 ignore(),你的问题就会消失。

    【讨论】:

    • 链接现在烂了:(
    • @sidewinderguy - 我遇到了完全相同的行为。我试着凝视上面 phresnel 的答案以收集一些关于它的知识,但“为什么”仍然让我难以理解。可惜链接失效了。 :(
    • 只有我一个人对“这就是为什么 C++ 应该死并让位给 Java”这句话感到震惊。 ?
    • 为哪个this?问题中的代码和错误消息不具有成员函数。
    • @Syndog:this 解决方案实际上对 OP 的情况没有帮助,所以约翰的回答是不正确的。但是,对于模板类成员函数(即模板类的成员函数(如 Foo::ignore()),this-&gt;ignore 强制编译器将 ignore 解释为 从属名称 仅在第 2 阶段完全查找。我的回答中解释了这背后的动机:)
    【解决方案3】:

    错误消息表示此时没有编译器可以使用的ignore 定义。如果这样做,您会得到完全相同的错误:

    void f() {
       g();
    }
    void g() {}
    

    ...即使看起来非常不同。请注意,正如其他答案所说,这里没有 ADL 问题。错误消息如此复杂的原因是编译器处理模板的方式。

    模板分两遍处理,在第一遍中,必须验证不依赖于实例化类型的所有内容不执行类型替换,在此遍中,必须检查每个非依赖名称,在这种情况下,编译器无法使用模板定义处可用的声明解析ignore

    如果表达式依赖于模板的类型参数,则不需要在第一次传递期间完全解析它,它会在类型替换后再次尝试,声明在实例化的地方。

    【讨论】:

    • 这是为我做的,9 年后哈哈
    【解决方案4】:

    我遇到了同样的问题,我已经通过更改包含顺序来解决它。

    正如 phresnel 所说,编译器无法在第一阶段解决该问题,在我的情况下,这是因为具有问题模板方法的标头包含在具有无法解决的内部方法的标头之前。

    添加所需的标头包含为我消除了错误。希望这对其他人有帮助。

    【讨论】:

      【解决方案5】:

      我不知道您的问题解决与否的天气,我希望它会解决。

      每当我遇到“没有依赖于模板参数的参数”的问题时,我都会重写该方法并调用父类成员函数。

      为了说明我的意思,考虑下面的一个类,它是模板类 ADT

      template <typename DataTypeOfNode>
      class LinearList
      {
      public:
          LinearList(){}
          void addAtBeg(DataTypeOfNode data) {
              //Inside implementation....
          }
          DataTypeOfNode removeFromFront() {
              //Inside implementation....
          } 
      
          // And many more useful methods
          ~LinearList(){}
      
      };
      

      现在如果你用基类继承这个类,就说 "PriorityQueue" 像这样

      template <typename DataTypeOfNode>
      class PriorityQueue : public LinearList<DataTypeOfNode>
      {
      public:
      
          void enqueue(DataTypeOfNode data){
              addAtBeg(data);
          }
      
          DataTypeOfNode dequeue(){
              return removeFromFront() ; 
          }
          PriorityQueue(){}
          ~PriorityQueue(){}
      };
      

      编译后,removeFromFront()addAtBeg() 方法将收到类似 “没有依赖于模板参数的参数” 之类的错误,因为它们具有模板参数。

      要修复这个错误,你只需要重写这些方法并像这样调用父类方法

      template <typename DataTypeOfNode>
      class PriorityQueue : public LinearList<DataTypeOfNode>
      {
      public:
      
          //Calling parent class methods
      
          void addAtBeg(DataTypeOfNode data){
              LinearList<DataTypeOfNode>::addAtBeg(data) ; 
          }
      
          DataTypeOfNode removeFromFront(){
              return LinearList<DataTypeOfNode>::removeFromFront() ; 
          }
      
          void enqueue(DataTypeOfNode data){
              addAtBeg(data);
          }
      
          DataTypeOfNode dequeue(){
              return removeFromFront() ; 
          }
          PriorityQueue(){}
          ~PriorityQueue(){}
      };
      

      【讨论】:

        【解决方案6】:

        这意味着编译器找不到ignore,ADL 无法启动。这意味着没有适当范围的ignore 函数。

        【讨论】:

          猜你喜欢
          • 2011-11-02
          • 2023-01-24
          • 2019-10-26
          • 1970-01-01
          • 2016-03-24
          • 1970-01-01
          • 2022-01-14
          • 2014-06-07
          • 2020-04-20
          相关资源
          最近更新 更多