【问题标题】:c++ function resolution selects templated version over plain functionc++ 函数解析选择模板版本而不是普通函数
【发布时间】:2015-04-23 18:33:28
【问题描述】:

考虑以下代码:

#include <iostream>

template<typename T>
void f(T t)
{
  (void)t;
  std::cout << "templated f(T)\n";
}

template<typename T>
void entry(T t)
{
  f(t);
}

void f(double d)
{
  (void)d;
  std::cout << "normal f(double)\n";
}

int main()
{
  double d = 0.0;
  entry(d);

  return 0;
}

输出:

模板化 f(T)

我觉得这很令人惊讶,因为我认为普通函数将被选择而不是任何模板版本。为什么会这样?

我在玩耍时注意到的另一件事是:如果我将普通函数 void f(double) 放在模板化 void entry(T) 函数之前,代码将调用普通函数,基本上输出:

正常 f(双)

因此我的另一个问题是:为什么在这个特定示例中顺序很重要?

【问题讨论】:

    标签: c++ function templates resolution


    【解决方案1】:

    f 是一个依赖名称,因为它依赖于类型为模板参数的t。依赖名称的名称查找规则在 [temp.dep.res]/1 中给出:

    在解析从属名称时,会考虑来自以下来源的名称:

    • 在模板定义处可见的声明。
    • 来自与函数参数类型关联的命名空间的声明 实例化上下文 (14.6.4.1) 和定义上下文。

    换句话说,通常在模板中查找名称只会查找在模板定义之前已声明的名称(这并不奇怪,因为它与非模板相同)。第二个要点允许找到在模板定义之后声明的名称,但仅在发生 ADL 时。如果参数是基本类型,例如 double,则不会出现这种情况。

    【讨论】:

    • 好的,...但是我注意到,如果模板是另一个模板,甚至是模板的特化,即使在模板声明 之后 之后,模板内的查找也会找到一个名称具有基本类型,例如double。我通过将普通函数更改为专用模板来检查这一点:template&lt;&gt; void f(double)。结果是调用了专门的模板,即使它超过了调用代码的声明点。
    • @Edenbridge 名称查找始终会找到主模板。特化的匹配发生在名称查找之后,并且具有不同的规则:如果模板在声明最佳匹配的部分特化之前被实例化,那么程序是病态的,不需要诊断。如果您还有其他问题,请发布一个单独的问题。
    【解决方案2】:

    在解析entry(T) 模板时,编译器看不到f(double) 的重载。因此,在实例化entry(T) 模板时,它不会参与重载决议。在解决模板实例化上下文中的重载时,这只是一个模糊的规则。为了考虑重载,它必须在模板定义被解析之前已经在翻译单元中可见。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多