如果没有实例化,为什么在模板中我们可以使用依赖名称而无需声明?
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
。所以它在实例化时是绑定的。
- 我在
foo
之后和 foo<int>
的专业化之前定义了 bar
,以便后者可以看到 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
}
那么允许在 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
从未实例化会发生什么,例如因为没有调用?嗯,程序仍然是错误的,但编译器可能不会告诉你。这是您使用 print
和 do_it
描述的行为,正式名称为 ill-formed,无需诊断.
我写这段代码是为了理解 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
。所以它在实例化时是绑定的。
- 我在
foo
之后和foo<int>
的专业化之前定义了bar
,以便后者可以看到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 }
那么允许在 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
从未实例化会发生什么,例如因为没有调用?嗯,程序仍然是错误的,但编译器可能不会告诉你。这是您使用 print
和 do_it
描述的行为,正式名称为 ill-formed,无需诊断.