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

Ram*_*uri 58 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;
}
Run Code Online (Sandbox Code Playgroud)

我必须从文件中读取所有内容.每个字段都按'\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 ===|
Run Code Online (Sandbox Code Playgroud)

Seb*_*ach 47

对于内置类型,不执行参数相关查找(ADL),因此,ignore必须将符号"导入"到当前名称空间中.

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

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

错误消息是这样出现的,因为在模板中,您还可以输入从属名称和两阶段查找的领域.依赖于模板参数的名称,例如

template <typename T> void foo() {
    T x;
    x.frobnicate();
}
Run Code Online (Sandbox Code Playgroud)

在阶段2中查找,这是在实例化时.不依赖于模板参数的名称,例如

class Foo {};

template <typename T> void foo() {
    Foo foo;
    foo.frobnicate();
}
Run Code Online (Sandbox Code Playgroud)

必须在第一阶段可以解决.

这种分离有助于模板作者更早发现错误并找到正确的符号,这有助于使模板更通用.例如,在C#泛型中,所有内容都必须是可解析的,这会对其灵活性施加相当严格的限制(因为必须定义泛型可能使用的所有内容).相反,一些旧的C++编译器仅在阶段2中解析,即在实例化时,这对于查找和错误发现具有一些微妙的后果.

C++ 2阶段模型结合了最好的eager模型(C#)和懒惰模型(一些旧的C++编译器).


小智 41

有关更简单的答案,请参阅 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(),你的问题就会消失.

  • 链接现在烂了:( (11认同)
  • 这有效!但我不确定我理解为什么. (4认同)
  • 我是唯一一个被句子震惊的人"这就是为什么C++应该死掉并让位给Java的原因." ? (4认同)
  • @Syndog:'this`解决方案实际上对OP的情况没有帮助,所以John的回答是不正确的.但是,在模板类成员函数(即模板类的成员函数(如Foo <T> :: ignore())的情况下,`this-> ignore`强制编译器将`ignore`解释为_dependent name_只在阶段2完全查找.这背后的动机在我的答案中解释:) (4认同)
  • @sidewinderguy - 我遇到了完全相同的行为.我试着凝视菲涅耳上面的回答来收集一些关于它的知识,但"为什么"仍然让我无法理解.链接已经死了太糟糕了.:( (2认同)
  • @BenoitBlanchon:不,你不是。虽然我认识到 C++ 语法的丑陋,但人们不能期望在不了解非常基本的错误消息和机制的情况下使用非常复杂的语言功能(“嘿,让我们编写一个模板化函数并成为一个酷孩子”)。不知道并没有什么错(我们都曾经一无所知,对吧?),但建议因为对高级功能的这种基本不了解而谋杀 C++ 充其量是无能的。“嘿,那些长名字和依赖倒置高潮是什么?这就是为什么 Java 应该......” (2认同)

Dav*_*eas 8

错误消息表示ignore此时编译器无法使用该定义.如果你这样做,那就是完全相同的错误:

void f() {
   g();
}
void g() {}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 这对我来说是成功的,9年后哈哈 (2认同)

Xav*_*ues 5

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

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

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