在定义模板后声明功能



假设我有一个模板函数:

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并成功完成的原因。


当人们相信所谓的"两相查找"的第二阶段时,这是一个相当普遍的误解模板定义一直到实例化点(在这种情况下调用的点)。

不,第二阶段看不到一切。它只能在与函数参数关联的名称空间中看到额外的东西。所有其他名称空间均未更新。它们被认为是从模板定义点观察到的。

最新更新