从另一个函数模板中调用未声明的函数模板

Calling undeclared function template from inside another function template

我正在学习 C++ 中的模板,因此尝试了不同的示例。下面给出了一个我无法理解其输出的示例:

template<typename T> void func(T p) {
g<T>(p); //ERROR
g(p);    //NO ERROR?
}


int main()
{

}

当我尝试编译上面的代码片段时,我得到 error 说:

prog.cc: In function 'void func(T)':
prog.cc:2:1: error: 'g' was not declared in this scope
    2 | g<T>(p); //ERROR
      | ^
prog.cc:2:4: error: expected primary-expression before '>' token
    2 | g<T>(p); //ERROR
      |    ^

我的问题是:

  1. 为什么会出现这个错误?
  2. 为什么我只收到语句 g<T>(p); 而不是 g(p); 的错误?我认为写 g(p); 等同于 g<T>(p);,因为由于模板参数推导,g 的模板参数将被推导为 T.

案例一

这里我们考虑语句:g<T>(p);

template<typename T> void func(T p) {
g<T>(p); //ERROR
}
int main()
{

}

在上面的代码片段中,名称 g 是一个 不合格的从属名称 。从 source: two phase lookup:

During the first phase, while parsing a template unqualified dependent names are looked up using the ordinary lookup rules. For unqualified dependent names, the initial ordinary lookup—while not complete—is used to decide whether the name is a template.

现在让我们将其应用于语句 g<T>(p);。在解析函数模板func时,遇到语句g<T>(p);。由于 g 是依赖限定名,根据上面引用的语句,使用 普通查找规则[=] 查找 名称 g 。这是为了让编译器可以决定名称 g 是否是一个模板。但是由于在这一点之前没有名为 g 的函数模板的声明,因此第一个尖括号 < 被视为 小于符号 并因此产生你提到的错误。另外,请注意 ADL 是在 第二阶段 中完成的。但要做到这一点,我们必须首先成功解析函数 func.[source 的通用定义:C++ 模板:完整指南:第 250 页倒数第二段]

请注意,允许编译器将错误延迟到实例化,这就是为什么某些编译器可以毫无错误地编译您的代码的原因。 Demo.

案例二

这里我们考虑语句g(p);.

template<typename T> void func(T p) {
g(p); // NO ERROR
}
int main()
{

}

在这种情况下,名称 g 也是一个 不合格的从属名称 。因此,根据我的回答开头引用的陈述,使用普通查找规则 查找 名称 g。但是由于此时没有 g visible 我们有一个错误。这里有两点需要注意:

  1. 因为这次你没有明确地(通过使用尖括号)调用 g,所以没有 语法错误
  2. 并且由于在这种情况下没有语法错误,并且在您的程序中没有 POI for func,所以这里没有错误可以延迟,并且程序编译正常。但是,如果您实例化 func 那么您将在实例化时收到错误提示 g was not declared.

模板使用 Two-phase name lookup.

First, at the point of the template definition, the template is checked for syntax.

所以 g(p); 是正确的(从语法的角度来看)(假设函数 gADL 找到)。

对于 g<T>(p);,我们有(直到 C++20):

Although a function call can be resolved through ADL even if ordinary lookup finds nothing, a function call to a function template with explicitly-specified template arguments requires that there is a declaration of the template found by ordinary lookup (otherwise, it is a syntax error to encounter an unknown name followed by a less-than character)

g<T>(p); 不正确,(仅解析为 (g < T) > p;T 是一种类型,因此是错误的))。

如果存在任何模板函数 g,则 g 可能被视为模板,并且从语法的角度来看代码是正确的(即使模板参数不匹配)。