如何解决有关默认参数
#include <iostream>
namespace J {
template <typename T> void zip(int = zap([] { })) { } //#1
template <typename T> int zap(const T &t) {return 0; }
}
int main(){
J::zip<long>();
}
考虑上面的代码,这是proposed resolution 1664的简化示例。注意标记为#1
的位置,我怀疑为什么可以在实例化上下文中查找zap
的名称。我认为zap
不是从属名称,从属名称的定义如下:
temp.dep
以以下形式的表达式:
postfix-expression(表达式列表 opt )
如果postfix-expression是unqualified-id,则unqualified-id表示从属名称,如果
- 表达式列表中的任何表达式都是包扩展,
- 表达式列表中的任何表达式或括号初始列表都是与类型相关的,或者
- unqualified-id是一个模板ID,其中任何模板参数都取决于模板参数。
我认为zap([] { })
不满足上述任何条件,因为表达式[] { }
的类型不是从属类型。尽管以下规则说与闭包类型关联的命名空间是按以下方式确定的:
temp.inst#11
如果以要求使用默认参数的方式调用函数模板f,则将查找从属名称,检查语义约束,并以默认方式使用默认参数中的任何模板进行实例化默认参数是在函数模板专门化中使用的初始化程序,具有与那时使用的函数模板f相同的作用域,相同的模板参数和相同的访问权限,但声明闭包类型的范围( [expr.prim.lambda.closure])及其相关的名称空间保持不变,具体取决于默认参数定义的上下文。这种分析称为默认参数实例化。然后,将实例化的默认参数用作f的参数。
但是,从模板定义的上下文和实例化的上下文来看,这些名称仅被考虑为从属名称,这由以下规则决定:
temp.dep.res
在解析从属名称时,将考虑以下来源的名称:
- 在模板定义时可见的声明。
- 来自实例化上下文([temp.point])和定义上下文中与函数参数类型关联的名称空间的声明。
使用常规名称查找并在使用它们的位置绑定找到模板定义中使用的非相关名称。
因此,我认为,为了遵守上述规则,zap
的名称查找仅在其使用时(即在#1
)进行,因为它不是从属的,名称,即完全不考虑实例化(ADL)上下文中的名称。
我在三种实现中测试代码,outcomes在下面列出:
- C语将
zap
视为一个从属名称。 - gcc
9.1
下的版本将zap
视为从属名称。 - 高于gcc
9.1
的版本将zap
视为非依赖名称,并且在实例化上下文中不执行zap
的名称查找。
那么,zap
的名称查找将经历什么确切的过程?在最新版本的gcc中,似乎同意将zap
作为非依赖性名称,这导致它找不到zap
的名称。如果我错过标准中的其他规则,不胜感激,请指出。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。