假设我有一个模板函数:
template <class T>
void tfoo( T t )
{
foo( t );
}
后来我想将其与类型一起使用,因此我声明/定义一个函数并尝试称呼它:
void foo( int );
int main()
{
tfoo(1);
}
我从g 出现错误:
在此范围内未宣布" foo",并且在实例化的点上没有发现任何声明[-fpermissive] foo(t);
为什么它在实例上找不到void foo(int)
?在这一点上被宣布。有没有办法使其正常工作(在模板之前不移动foo
声明)?
foo
在您的情况下为依赖性名称,因为函数选择取决于参数和参数类型取决于模板参数,取决于类型。这意味着 foo
是根据依赖的查找。
依赖和非依赖性查找之间的差异是,在依赖查找的情况下扩展:从模板实例化中可见额外的名称(在您的情况下为tfoo
调用)。其中包括在模板声明之后出现的名称。这里的要点是唯一以这种方式扩展了 adl提名的名称空间。
(通过 adl提名的命名空间我是指与函数参数类型关联的命名空间,因此由依赖名称查找规则进行了考虑。请参见" 3.4.2与参数有关的名称查找")
在您的情况下,参数具有int
类型。int
是一种基本类型。基本类型没有关联的名称空间(请参阅" 3.4.2参数依赖性名称查找"),这意味着它不会通过ADL提名任何名称空间。在您的示例中,ADL根本不涉及。在这种情况下,foo
的依赖名称与非依赖性查找没有什么不同。它将看不到您的foo
,因为它在模板下方声明。
请注意以下示例的区别
template <class T> void tfoo( T t )
{
foo( t );
}
struct S {};
void foo(S s) {}
int main()
{
S s;
tfoo(s);
}
此代码将编译,因为参数类型S
是类类型。它具有关联的名称空间 - 全局一个空间 - 并添加了(提名)该依赖名称查找的全局名称空间。通过其更新的表单中的依赖查找(从呼叫的点可以看出),可以看到此类提名的名称空间。这就是为什么查找可以看到foo
并成功完成的原因。
当人们相信所谓的"两相查找"的第二阶段时,这是一个相当普遍的误解模板定义一直到实例化点(在这种情况下调用的点)。
不,第二阶段看不到一切。它只能在与函数参数关联的名称空间中看到额外的东西。所有其他名称空间均未更新。它们被认为是从模板定义点观察到的。