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

发布于 2024-12-21 11:57:25 字数 1344 浏览 2 评论 0原文

这段代码应该如何表现?如果我在 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

How should this code behave? It calls generic function ignoring my overload if I use qualified name in call_read() function; and it calls overload first and then generic version if I use unqualified name. What's the difference? Is it a bug in 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);
}

I also noticed that it works different for fundamental types.
See the code bellow

#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());
}

It is supposed to call overloaded function twice, but it's not.
See the result here
http://codepad.org/iFOOFD52

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

感情洁癖 2024-12-28 11:57:25

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

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

[...] 在以下形式的表达式中:

后缀表达式 ( expression-listopt )

其中后缀表达式是标识符,当且仅当表达式列表中的任何表达式是依赖于类型的表达式 (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)的查找部分,仅在模板定义上下文或模板<中找到具有外部链接的函数声明找到了strong>实例化上下文。

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

What you're observing is a superposition of two-phase name lookup and argument dependent lookup.

Let's see what the standard says (C++03). [temp.dep]:

[...] In an expression of the form:

postfix-expression ( expression-listopt )

where the postfix-expression is an identifier, the identifier denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2).

That means that in both read and ::read, read is a dependent name because x is type-dependent. That means that it's resolved at the point of instantiation. Let's see what are the rules for this [temp.dep.candidate]:

For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2) except that:

— For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the template definition context are found.

Therefore for the ::read case only functions declared before the template definition are considered. But:

— For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the template definition context or the template instantiation context are found.

for the unqualified read both functions are considered, those visible at template definition and template instantiation.

风轻花落早 2024-12-28 11:57:25

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

编辑:由于对于像 intdouble 这样的基本类型没有 ADL,这解释了你的第二个观察结果。

Yes, this is the expected behaviour. In the first case (::read) you effectivly disable ADL (argument dependent lookup) which restricts name lookup to things that have been declared in the global scope before your use of read. If you remove :: ADL will kick which may resolve to functions you declared after your function template.

Edit: And since for fundamental types like int and double there is no ADL, this explains your 2nd observation.

二智少女 2024-12-28 11:57:25

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

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

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

对于问题的第二部分,关于使用完全限定名称和非限定名称时的差异,它来自以下事实:完全限定名称不依赖于其他任何内容,因此解析为第一个匹配项(此处是您的模板声明)。

The compiler will always call the method which match the most your call. Here you call :

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

Thus the compiler will prefer the overload as it precisely match the call. It in the logic of template specializations, which permits to say that if an overloaded function exists which better match your call, then this one will be used.

For the second part of the question, concerning the difference when using fully-qualified and unqualified names, it comes from the fact that fully-qualified name is not dependent to anything else, and is thus resolved to the first match (here your template declaration).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文