模板中的名称解析

时间:2009-07-08 11:31:28

标签: c++ templates

我正在阅读模板名称解析here。只是为了了解我复制代码的事情:

void f (char c)
{
    std::cout<<"f(char)\n";
}
template <class T>
void g(T t)
{
    f(1);
    f(T(1));
    f(t);

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

void test()
{
    std::cout<<"First call\n";
    g(1);

    std::cout<<"Second call\n";
    g('a');
}

int main()
{
    test();
    return 0;
}

根据链接的文章,我应该为d ++语句编译错误。同样对于第一次调用g(1),我应该调用f(char),然后调用两次f(int),对于第二次调用,我应该调用f(char)三次。但是,当我使用Vs2008编译它时,它编译正常没有任何错误。此外,输出是:

  

先致电

     

F(INT)

     

F(INT)

     

F(INT)

     

第二次电话

     

F(INT)

     

F(char)的

     

F(char)的

我现在想知道哪一个是正确的?我链接的文章或VS2008输出?任何正确的线索?

4 个答案:

答案 0 :(得分:3)

关于d++是否应该编译,这篇文章是正确的。

Visual C ++不进行两阶段模板实例化 - 它几乎完成了在实例化时的所有解析。

Gcc和Comeau会给出正确的错误,并会调用正确的f

答案 1 :(得分:3)

尽管VS2008被认为是当时最符合标准的C ++编译器,但在这里我们有一个接受无效代码的实例。 G ++不编译它(d ++:错误:'d'未在此范围内声明)。也就是说,任何依赖于C ++语言错综复杂的程序都会被打破:)

答案 2 :(得分:3)

  

同样对于第一次调用g(1),我应该调用f(char),然后调用两次f(int),对于第二次调用,我应该调用三次f(char)。 / p>

这不是符合标准的编译器的预期结果。既然你用基本类型调用它,你将在函数调用的实例化上下文中获取名称。

实例化上下文中的名称查找仅发生在依赖于参数的查找(使用关联的命名空间查找查找)中。 intchar都没有参数依赖查找,因此 all 您删除{{1}后调用f(char)的函数调用行。


因为我知道你不可能只相信我,所以这是标准引用,d++

  

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

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

请注意,该文章使用标准的缺陷示例(14.6.4.2)(并注意示例是非规范性的:它们不能更改或陈述规则。它们的目的完全是说明性的)。该缺陷已得到修复,并纳入即将出台的标准中。请参阅this defect report


如您所见,您必须从14.6/9 / int更改为某些用户定义的类型(枚举或类),也可以在实例化上下文中查看查找的效果。请阅读此答案Order affects visibility以获取更多信息。

答案 3 :(得分:1)

VS应该抱怨d ++,因为d应该在定义点上查找。

文章不正确,调用应解析为f(char),因为不应对基本类型进行实例化查找(参见tlib answer)。

g ++行为取决于版本:

  • 在3.4之前,它始终指向实例化查找,这是一个错误。

  • 从3.4开始,它确定了d的定义查找点;但确实如此 当基本类型是模板参数时,实例化查找它们 是一个错误。

  • 从4.1开始,它不再对基本类型进行实例化查找。