用于模板的限定和非限定名称查找的不同行为

axe*_*axe 14 c++ lookup templates language-lawyer argument-dependent-lookup

这段代码应该如何表现?如果我在函数中使用限定名称,它会调用泛型函数忽略我的重载call_read(); 如果我使用非限定名称,它首先调用重载然后调用泛型版本.有什么不同?这是海湾合作委员会的一个错误吗?

#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);
}
Run Code Online (Sandbox Code Playgroud)

我也注意到它对基本类型有所不同.请参阅下面的代码

#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());
}
Run Code Online (Sandbox Code Playgroud)

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

ybu*_*ill 9

您所观察到的是两阶段名称查找参数相关查找的叠加.

让我们看看标准所说的内容(C++ 03).[temp.dep]:

[...]表达形式:

postfix-expression ( expression-listopt )
Run Code Online (Sandbox Code Playgroud)

其中postfix-expression是标识符,当且仅当表达式列表中的任何表达式是依赖于类型的表达式时,标识符表示从属名称(14.6.2.2).

这意味着,在这两个read::read,read是一个从属名称,因为x是类型相关.这意味着它在实例化时得到了解决.让我们看看这个[temp.dep.candidate]的规则是什么:

对于依赖于模板参数的函数调用,如果函数名称是unqualified-id但不是template-id,则使用通常的查找规则(3.4.1,3.4.2)找到候选函数,除了:

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

因此,::read仅考虑在模板定义之前声明的函数.但:

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

对于不合格的read两个函数都被考虑,那些在模板定义和模板实例化时可见.

  • 我不认为这是真的.x始终是一个从属名称,它将查找延迟到第二阶段.区别在于一种语法禁用ADL而另一种语法禁用ADL.你不同意吗? (2认同)

sel*_*tze 5

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

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