【问题标题】:Declare function after template defined定义模板后声明函数
【发布时间】:2016-11-29 20:45:09
【问题描述】:

假设我有一个模板函数:

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

稍后我想将它与类型一起使用,因此我声明/定义了一个函数并尝试调用它:

void foo( int );

int main()
{
    tfoo(1);
}

我从 g++ 收到错误:

‘foo’未在此范围内声明,并且在实例化点通过依赖于参数的查找未找到任何声明 [-fpermissive] 富(t);

为什么在实例化时找不到void foo(int)?它是在那个时候声明的。有没有办法让它工作(无需在模板之前移动foo 的声明)?

【问题讨论】:

  • 不是因为the two phase lookup吗?
  • @W.F.实际上,由于两阶段查找,我希望它能够编译。
  • 或许在函数模板中声明你要调用的函数会为你解决问题?
  • 在我与 AnT 和 W.F. 的对话之后。在 cmets 中,带有允许使用 ADL 调用 foo 的转换运算符的包装器怎么样?像这样:coliru.stacked-crooked.com/a/dc92e572d02f601a

标签: c++ name-lookup


【解决方案1】:

foo 在您的情况下是一个从属名称,因为如果参数和参数类型取决于模板参数,则函数选择取决于类型。这意味着foo是按照依赖查找的规则查找的。​​p>

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

(通过ADL-nowned命名空间我指的是命名空间关联函数参数类型,因此被依赖名称查找的规则考虑在内。参见“3.4.2依赖于参数的名称查找")

在您的情况下,参数的类型为intint 是基本类型。基本类型没有关联的命名空间(参见“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 是一个类类型。它有一个关联的命名空间 - 全局命名空间 - 它添加(指定)该全局命名空间以进行相关名称查找。这种 ADL 命名的命名空间可以通过依赖查找以它们的更新 形式看到(从调用点来看)。这就是查找可以看到foo 并成功完成的原因。


当人们认为所谓的“双阶段查找”的第二阶段应该能够看到下面另外声明的所有内容时,这是一个相当普遍的误解模板定义一直到实例化点(在本例中为调用点)。

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

【讨论】:

  • 如果我将T 的类型更改为某个类,那么该类的命名空间不应该也进来吗? it doesn't 所以我显然不明白一些东西。只有当foo 接受依赖类型时,它似乎也被引入了。
  • @AndyG:你是对的。如果foo 与实际T 在同一个命名空间中,那么它应该被引入。这适用于类类型。这适用于枚举类型。依此类推(见 3.4.2)。这对基本类型不起作用
  • @AnT,那你能解释一下为什么我在第一条评论中链接的代码无法编译吗?
  • @W.F.:这是一个关键的区别:ADL 由调用中使用的立即参数类型定义,在任何转换之前。显然,编译器在实际找到foo(int) 并确定foo(int) 是最佳(唯一)候选者之前,无法知道参数将被转换为int
  • @W.F.:您之前的评论(由于某种原因被您删除)涉及一个带有默认参数的函数。默认参数 (DA) 不能影响名称查找,原因与用户定义的转换 (UDC) 不能影响名称查找的原因相同。 DA 和 UDC 在重载分辨率期间(或之后)都发挥作用。只有在名称查找完成 之后才能解决重载问题。由于这个原因,DA 和 UDC 不可能影响名称查找。在名称查找阶段,尚不清楚可用的 DA 和 UDC。
猜你喜欢
  • 2021-03-24
  • 1970-01-01
  • 1970-01-01
  • 2014-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多