该函数调用是否应该模棱两可?

时间:2019-06-08 01:03:03

标签: c++ argument-dependent-lookup function-templates name-lookup

前几天,我偶然跌跌撞撞,无法弄清楚哪个答案是正确的,或者都不能接受。

具体地说,我指的是对OtherFunction中的bar(T {})的调用。从我已经能够在编译器资源管理器上进行测试的角度来看,这个决定似乎有些分歧。 msvc和icc同意,在gcc和clang编译代码而不会出现问题时,它是模棱两可的。

通过与参数相关的查找,隐藏的命名空间内的功能栏变得可见。此外,msvc / icc将全局命名空间中的bar声明视为候选,而gcc / clang则不这样做。似乎不应该考虑全局命名空间中的声明,因为它是在调用bar(T {})之后声明的,但是我不确定我是在正确读取不合格名称查找的规则还是标准是在这方面模棱两可。

https://godbolt.org/z/HAS-Cv

编辑: 看起来只要使用/ permissive-选项,msvc就可以解决此问题 (https://devblogs.microsoft.com/cppblog/two-phase-name-lookup-support-comes-to-msvc/

    int num1;
    bool res = int.TryParse(txtUprice.Text, out num1);
    if (res == false)
    {
        MessageBox.Show("String is not a number");
    }
    else{
        MessageBox.Show(num1.ToString()); 
    }

2 个答案:

答案 0 :(得分:3)

Gcc和Clang是正确的。 name lookup无法找到在bar定义之后定义的全局OtherFunction;而ADL可以找到hidden::bar

(重点是我的)

  

对于模板定义中使用的从属名称,查找将推迟到知道模板参数为止,这时ADL将检查在模板定义上下文以及模板中可见的函数声明with external linkage (until C++11)实例化上下文,而非ADL查找仅检查从模板定义上下文可见的函数声明with external linkage (until C++11)(换句话说,在模板定义之后添加新的函数声明不会使其可见,除非通过ADL < / strong>)。

答案 1 :(得分:2)

该代码有效,因此msvc和icc不正确。

由于bar的参数是类型相关的,因此名称bar是从属名称,并且仅在实例化模板OtherFunction时才查找,而在模板{定义。

C ++ 17 [temp.dep.candidate] / 1:

  

对于 postfix-expression 是从属名称的函数调用,使用常规查找规则([basic.lookup.unqual],[basic.lookup.argdep] ),除了:

     
      
  • 对于使用非限定名称查找([basic.lookup.unqual])进行的查找,仅从模板定义上下文中找到函数声明。

  •   
  • 对于使用关联命名空间([basic.lookup.argdep])进行的查找,仅从模板定义上下文或模板实例化上下文中找到函数声明。

  •   

所以跳到[basic.lookup.argdep] / 3:

  

X 是由不合格查找([basic.lookup.unqual])产生的查找集,而让 Y 是由参数依赖查找(定义为如下)。如果 X 包含

     
      
  • 类成员的声明,或
  •   
  • 不是 using-declaration
  • 的块范围函数声明   
  • 既不是函数也不是函数模板的声明
  •   
     

然后 Y 为空。否则, Y 是在与参数类型关联的名称空间中找到的声明集,如下所述。通过名称查找发现的声明集是 X Y 的并集。

[当前的C ++ 20草案在这些部分中重新排列了措词。特别是,现在在[basic.lookup.argdep]/4.5中列出了有关在关联的命名空间中包含用于查找从属名称的实例化上下文的规则,而在[temp.dep.candidate]中只是一个 Note 。我不确定这样做的原因是为了清楚,还是可能与模块的效果有关。]

X 是对名称bar的不合格查找的结果,仅考虑从模板定义上下文可见的声明。但是,由于模板定义上下文是翻译单元的最开始,因此 X 很明显是空的。

由于 X 根本不包含任何内容,因此它不包含列出的会强制 Y 为空的项目。因此,要确定 Y ,我们查看与参数类型关联的名称空间。此实例中的参数类型为hidden::Foo,因此唯一关联的命名空间为hidden,名称查找的唯一结果是函数hidden::bar

::bar在此名称查找中不可见,因此bar(T{})表达式不能模棱两可。