为什么在模板中,如果未实例化,我们可以在不声明的情况下使用依赖名称?

Why in a template we can use a dependent name without being already declared if not instantiated?

提问人:Maestro 提问时间:10/26/2020 更新时间:10/26/2020 访问量:80

问:

我写了这段代码来理解名称查找:template

//void bar(int);

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

void bar(int x)
{
    std::cout << "bar(int)\n";
}

template <int>
void foo(int i)
{
    bar(i);
}



int main()
{

    foo<int>(4);


    std::cout << "\ndone!\n";
}

我故意注释掉了函数的声明。此函数用作模板函数。因此,它在实例化时被绑定。bar(int)bar(int)dependent namefoo

  • 我已经在专门化之后和之前定义了,以便后者可以看到.barfoofoo<int>bar(int)

但是当我编译代码时,出现此错误:

‘bar’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]|.如果我取消评论,它的声明工作正常?!bar(int)

  • 如果我必须在模板中将其用作依赖名称之前声明一个名称,那么为什么 C++ 允许它(如果没有实例化)。(如果我不“使用”模板化函数,代码有效)?foo

      template <typename U>
      void do_it(U u)
      {
          print(u); // not bound until instantiation
      }
    

那么,允许尚未声明且在实例化时会失败的调用背后的想法是什么?print(u)do_it

C++ 模板 dependent-name

评论

2赞 cigien 10/26/2020
print(u)实际上是不允许的。只是您不一定会收到错误消息。
0赞 Maestro 10/26/2020
@idclev463035818:因为它使用了模板参数类型。
0赞 463035818_is_not_an_ai 10/26/2020
哦,对了,我的错。
1赞 cigien 10/26/2020
嗯,我想我明白你的困惑在哪里了。你根本没有专业化。您声明的是一个完全不同的实体。你需要代码就可以了。footemplate<> void foo<int>(int i);

答:

1赞 Timothy Brackett 10/26/2020 #1

请注意该错误输出中的行号。

您正在实例化第一个模板。第二个模板不是第一个模板的规范,而是一个函数模板,它需要一个不使用的模板参数。int

评论

0赞 Maestro 10/26/2020
谢谢!输出中的错误号是什么意思?
2赞 Timothy Brackett 10/26/2020
警告和错误通常具有与之关联的行号。 例如,是 的第 128 行。file.cpp:128file.cpp
3赞 cigien 10/26/2020 #2

在您的程序中,此定义:

template <int>     // not a specialization, just a different
void foo(int i)    // template with a non-type template parameter
{
    bar(i);
}

实际上并未定义主模板的专用化。因此,当您进行此调用时:foo

Foo<int>(4);

您最终会调用主模板。查找名称找不到该名称,并且出现错误。bar

相反,你实际上写了一个这样的专业化:fooint

template <>           // specialization of primary
void foo<int>(int i)  // template foo with int
{
    bar(i);
}

然后调用就可以了,因为它调用了专用化,并且 Lookup for 在此时确实找到了该名称。foo<int>(4);bar


现在回到您的程序(没有专用化),例如,如果从未实例化,因为没有调用,会发生什么?好吧,程序仍然是错误的,但编译器可能不会告诉你。这是您用 和 描述的行为,这在形式上称为格式错误,不需要诊断fooprintdo_it