模板定义

时间:2016-11-29 20:45:09

标签: c++ name-lookup

我们说我有一个模板功能:

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的声明)?

1 个答案:

答案 0 :(得分:8)

在您的情况下,

foo依赖名称,因为如果参数和参数类型取决于模板参数,函数选择取决于类型。这意味着根据依赖查找的规则查找foo

依赖非依赖查找之间的区别在于,在依赖查找的情况下 ADL指定的名称空间被视为扩展:从模板实例化(tfoo调用的情况下)可见的额外名称扩展它们。这包括模板声明后出现的名称。这里的关键点是 ADL指定的命名空间以这种方式扩展。

(通过 ADL指定的命名空间我引用与函数参数类型相关联的命名空间,因此通过依赖名称查找的规则来考虑。参见&#34; 3.4.2依赖于参数的名称查找&#34;)

在您的情况下,参数的类型为intint是一种基本类型。基本类型没有关联的命名空间(参见&#34; 3.4.2依赖于参数的名称查找&#34;),这意味着它没有通过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是类类型,因此将编译此代码。它有一个关联的命名空间 - 全局命名空间 - 它添加(指定)用于依赖名称查找的全局命名空间。这些ADL指定的命名空间可通过依赖查找以其更新的形式看到(从调用的角度看)。这就是查找可以看到foo并成功完成的原因。

当人们相信所谓的&#34;两阶段查找的第二阶段时,这是一种相当普遍的误解。应该能够看到在模板定义下面另外声明的所有一直到实例化的地方(在这种情况下是调用点)。

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