没有依赖于模板参数的参数

时间:2012-03-30 11:22:51

标签: c++ templates

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

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 ===|

6 个答案:

答案 0 :(得分:46)

对于内置类型,不执行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阶段模型结合了最好的热切模型(C#)和懒惰模型(一些旧的C ++编译器)。

答案 1 :(得分:34)

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

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

答案 2 :(得分:7)

错误消息表示编译器此时没有ignore的定义。如果你这样做,那就完全一样了:

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

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

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

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

答案 3 :(得分:3)

我遇到了同样的问题,我通过更改包含顺序修复了它。

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

添加所需的标题包括为我删除了错误。希望这有助于其他人。

答案 4 :(得分:2)

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

每当我遇到&#34;没有依赖于模板参数的参数&#34; 时,我会覆盖该方法并调用父类成员函数。

要显示我的意思,请考虑下面的类是模板类ADT

template <typename DataTypeOfNode>
class LinearList
{
public:
    LinearList(){}
    void addAtBeg(DataTypeOfNode data) {
        //Inside implementation....
    }
    DataTypeOfNode removeFromFront() {
        //Inside implementation....
    } 

    // And many more useful methods
    ~LinearList(){}

};

现在,如果你继承了这个基类的类,说&#34; PriorityQueue&#34; 就像这样

template <typename DataTypeOfNode>
class PriorityQueue : public LinearList<DataTypeOfNode>
{
public:

    void enqueue(DataTypeOfNode data){
        addAtBeg(data);
    }

    DataTypeOfNode dequeue(){
        return removeFromFront() ; 
    }
    PriorityQueue(){}
    ~PriorityQueue(){}
};

在编译之后,您将收到类似&#34的错误;没有任何参数依赖于removeFromFront()addAtBeg()方法的模板参数&#34; ,因为他们有模板参数。

要修复此错误,您只需要覆盖这些方法并调用像这样的父类方法

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(){}
};

答案 5 :(得分:1)

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