14

这段代码应该如何表现?如果我在函数中使用限定名,它会调用通用函数而忽略我的重载call_read()如果我使用非限定名称,它首先调用重载,然后调用通用版本。有什么不同?它是 GCC 中的错误吗?

#include <iostream>

struct info1 {};
struct info2 {};

template<class T> void read(T& x)
{
   std::cout << "generic" << std::endl;
}

template<class T> void call_read(T& x)
{
   ::read(x); // if I replace ::read(x) with read(x) the overload is called
}

void read(info1& x)
{
   std::cout << "overload" << std::endl;
}

int main()
{
   info1 x;
   info2 y;
   call_read(x);
   call_read(y);
}

我还注意到它对基本类型的工作方式不同。见下面的代码

#include <iostream>

typedef struct info1 {};
typedef struct info2 {};
typedef int info3;
typedef double info4;

template<class T> void read(T x)
{
    std::cout << "generic" << std::endl;
}

template<class T> void call_read(T x)
{
    read(x);
}

void read(info1 x)
{
    std::cout << "overload" << std::endl;
}
void read(info3 x)
{
    std::cout << "overload" << std::endl;
}

int main()
{
    call_read(info1());
    call_read(info2());
    call_read(info3());
    call_read(info4());
}

它应该调用两次重载函数,但事实并非如此。在此处查看结果 http://codepad.org/iFOOFD52

4

3 回答 3

9

您正在观察的是两阶段名称查找参数相关查找的叠加。

让我们看看标准是怎么说的(C++03)。[温度.dep]:

[...] 形式的表达:

postfix-expression ( expression-listopt )

其中后缀表达式是一个标识符,当且仅当表达式列表中的任何表达式是一个依赖于类型的表达式 (14.6.2.2) 时,该标识符才表示一个依赖名称。

这意味着在两者中read,::read都是read一个依赖名称,因为x它依赖于类型。这意味着它在实例化时已解决。让我们看看这个 [temp.dep.candidate] 的规则是什么:

对于依赖于模板参数的函数调用,如果函数名称是非限定 ID 但不是模板 ID,则使用通常的查找规则(3.4.1、3.4.2)找到候选函数,但以下情况除外:

— 对于使用非限定名称查找 (3.4.1) 的查找部分,仅找到具有来自模板定义上下文的外部链接的函数声明。

因此,对于这种::read情况,只考虑在模板定义之前声明的函数。但:

— 对于使用关联命名空间(3.4.2) 的查找部分,仅找到在模板定义上下文或模板实例化上下文中找到的具有外部链接的函数声明。

对于不合格的read两个函数,在模板定义和模板实例化中可见。

于 2011-12-14T08:30:09.037 回答
5

是的,这是预期的行为。在第一种情况下(::read),您有效地禁用了 ADL(依赖于参数的查找),它将名称查找限制为在使用 read之前已在全局范围内声明的内容。如果您删除 :: ADL 将启动,这可能会解析为您在函数模板之后声明的函数。

编辑:因为对于基本类型,比如int并且double没有 ADL,这解释了你的第二个观察。

于 2011-12-14T08:33:02.557 回答
-1

编译器将始终调用与您的调用最匹配的方法。你在这里打电话:

read(T& x) [with T = info1]

因此编译器会更喜欢重载,因为它与调用精确匹配。它在模板专业化的逻辑中,它允许说如果存在更匹配您的调用的重载函数,那么将使用这个。

对于问题的第二部分,关于使用完全限定名称和非限定名称时的区别,它来自这样一个事实,即完全限定名称不依赖于其他任何东西,因此被解析为第一个匹配项(这里是您的模板声明)。

于 2011-12-14T08:31:42.730 回答