如果没有实例化,为什么在模板中我们可以使用依赖名称而无需声明?

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

我写这段代码是为了理解 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) 在模板函数 foo 中用作 dependent name。所以它在实例化时是绑定的。

但是当我编译代码时出现这个错误:

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

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

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

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

在你的程序中,这个定义:

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 未找到该名称,您收到错误消息。

如果相反,您实际上为 int 编写了 foo 的特化,如下所示:

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

那么调用 foo<int>(4); 就可以了,因为它调用了专业化,并且在那个时候查找 bar 确实找到了那个名字。


现在回到您的程序(没有专门化),如果 foo 从未实例化会发生什么,例如因为没有调用?嗯,程序仍然是错误的,但编译器可能不会告诉你。这是您使用 printdo_it 描述的行为,正式名称为 ill-formed,无需诊断.