定义模板后声明功能 [英] Declare function after template defined

查看:96
本文介绍了定义模板后声明功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个模板函数:

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在您的情况下是依赖的名称,因为如果参数和参数类型取决于函数选择,则函数选择取决于类型在template参数上.这意味着foo是根据依赖查找的规则查找的.

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

(通过 ADL提名的命名空间,我指的是与函数参数类型相关联的命名空间,因此被从属名称查找规则所考虑.请参阅"3.4.2与参数相关的名称查找")

在您的情况下,参数的类型为int. int是基本类型.基本类型没有关联的名称空间(请参阅"3.4.2基于参数的名称查找"),这意味着它不会通过ADL提名任何名称空间.在您的示例中,根本不涉及ADL.在这种情况下,foo的从属名称查找与非从属查找没有区别.由于将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提名的名称空间可以通过 updated 形式的依赖查找来看到(从调用的角度来看).这就是查找可以看到foo并成功完成的原因.


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

否,第二阶段无法看到所有内容.它只能在与函数参数关联的命名空间中看到额外的东西 .所有其他名称空间都不会更新.从模板定义的角度看,它们就像被观察到一样.

Let's say I have a template function:

template <class T>
void tfoo( T t )
{
    foo( t );
}

later I want to use it with a type, so I declare/define a function and try to call it:

void foo( int );

int main()
{
    tfoo(1);
}

and I am getting error from g++:

‘foo’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] foo( t );

why it cannot find void foo(int) at the point of instantiation? It is declared at that point. Is there a way to make it work (without moving declaration of foo before template)?

解决方案

foo in your case is a dependent name, since function choice depends on the type if the argument and the argument type depends on the template parameter. This means that foo is looked up in accordance with the rules of dependent lookup.

The difference between dependent and non-dependent lookup is that in case of dependent lookup ADL-nominated namespaces are seen as extended: they are extended with extra names visible from the point of template instantiation (tfoo call in your case). That includes the names, which appeared after the template declaration. The key point here is that only ADL-nominated namespaces are extended in this way.

(By ADL-nominated namespace I refer to namespace associated with function argument type and therefore brought into consideration by the rules of dependent name lookup. See "3.4.2 Argument-dependent name lookup")

In your case the argument has type int. int is a fundamental type. Fundamental types do not have associated namespaces (see "3.4.2 Argument-dependent name lookup"), which means that it does not nominate any namespace through ADL. In your example ADL is not involved at all. Dependent name lookup for foo in this case is no different from non-dependent lookup. It will not be able to see your foo, since it is declared below the template.

Note the difference with the following example

template <class T> void tfoo( T t )
{
    foo( t );
}

struct S {};

void foo(S s) {}

int main()
{
    S s;
    tfoo(s);
}

This code will compile since argument type S is a class type. It has an associated namespace - the global one - and it adds (nominates) that global namespace for dependent name lookup. Such ADL-nominated namespaces are seen by dependent lookup in their updated form (as seen from the point of the call). This is why the lookup can see foo and completes successfully.


It is a rather widespread misconception when people believe that the second phase of so called "two-phase lookup" should be able to see everything that was additionally declared below template definition all the way to the point of instantiation (point of the call in this case).

No, the second phase does not see everything. It can see the extra stuff only in namespaces associated with function arguments. All other namespaces do not get updated. They are seen as if observed from the point of template definition.

这篇关于定义模板后声明功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆