C++ 20 中 decl-reachable 是什么?

YZ_*_*_SO 7 c++ language-lawyer c++20 c++-modules

\xc2\xa710.4/3详细给出了 decl-reachable 所有可能的情况。然而,我无法完全理解它。考虑\xc2\xa710.4/6中描述的示例:

\n
Source file "foo.h":\n  namespace N {\n  struct X {};\n  int d();\n  int e();\n  inline int f(X, int = d()) { return e(); }\n  int g(X);\n  int h(X);\n}\n\nModule M interface:\nmodule;\n#include "foo.h"\nexport module M;\ntemplate<typename T> int use_f() {\n  N::X x;                       // N\xe2\x80\x8b::\xe2\x80\x8bX, N, and \xe2\x80\x8b::\xe2\x80\x8b are decl-reachable from use_\xc2\xadf\n  return f(x, 123);             // N\xe2\x80\x8b::\xe2\x80\x8bf is decl-reachable from use_\xc2\xadf,\n                                // N\xe2\x80\x8b::\xe2\x80\x8be is indirectly decl-reachable from use_\xc2\xadf\n                                //   because it is decl-reachable from N\xe2\x80\x8b::\xe2\x80\x8bf, and\n                                // N\xe2\x80\x8b::\xe2\x80\x8bd is decl-reachable from use_\xc2\xadf\n                                //   because it is decl-reachable from N\xe2\x80\x8b::\xe2\x80\x8bf\n                                //   even though it is not used in this call\n}\ntemplate<typename T> int use_g() {\n  N::X x;                       // N\xe2\x80\x8b::\xe2\x80\x8bX, N, and \xe2\x80\x8b::\xe2\x80\x8b are decl-reachable from use_\xc2\xadg\n  return g((T(), x));           // N\xe2\x80\x8b::\xe2\x80\x8bg is not decl-reachable from use_\xc2\xadg\n}\ntemplate<typename T> int use_h() {\n  N::X x;                       // N\xe2\x80\x8b::\xe2\x80\x8bX, N, and \xe2\x80\x8b::\xe2\x80\x8b are decl-reachable from use_\xc2\xadh\n  return h((T(), x));           // N\xe2\x80\x8b::\xe2\x80\x8bh is not decl-reachable from use_\xc2\xadh, but\n                                // N\xe2\x80\x8b::\xe2\x80\x8bh is decl-reachable from use_\xc2\xadh<int>\n}\nint k = use_h<int>();\n  // use_\xc2\xadh<int> is decl-reachable from k, so\n  // N\xe2\x80\x8b::\xe2\x80\x8bh is decl-reachable from k\n\nModule M implementation:\nmodule M;\nint a = use_f<int>();           // OK\nint b = use_g<int>();           // error: no viable function for call to g;\n                                // g is not decl-reachable from purview of\n                                // module M\'s interface, so is discarded\nint c = use_h<int>();           // OK\n\n
Run Code Online (Sandbox Code Playgroud)\n

为什么N\xe2\x80\x8b::\xe2\x80\x8bg从 无法 decl-reachable use_\xc2\xadg?为什么N\xe2\x80\x8b::\xe2\x80\x8bhdecl-reachable from 不是use_\xc2\xadh,但N\xe2\x80\x8b::\xe2\x80\x8bhdecl-reachable from use_\xc2\xadh<int>?为什么 \xc2\xa710.4/(3.2) 或 \xc2\xa710.4/(3.3) 不适用于它们?

\n

Bri*_*ian 6

N::f is decl-reachable from use_f due to rule 10.4.3.2.

In determining whether N::g is reachable from use_g, we find that neither 10.4.3.2 nor 10.4.3.3 applies.

  • 10.4.3.2 does not apply because g((T(), x)) is a dependent call and thus, at the point of declaration of the template use_g, it can't be determined yet which function is actually named by the call. (It will be determined when use_g is instantiated, but in that case it may only imply that N::g is reachable from that particular specialization of use_g, not the template use_g itself.)
  • 10.4.3.3 instructs us to consider a hypothetical call to g where each type-dependent argument is replaced by an expression of a type that has no associated namespaces or entities. Thus, for example, we could replace (T(), x) by 0, giving the hypothetical call g(0). This would not find N::g during the name lookup phase, so it doesn't make N::g decl-reachable.

出于类似的原因,N::h无法从 中 decl-reachable use_h

use_h<int>被实例化时,规则 10.4.3.2 适用。此时,编译器确定 的类型(T(), x)N::X,并实际执行 的名称查找hN::h通过依赖于参数的查找进行查找。也就是说,在此特定专业化中h((T(), x))命名函数(其中= ),但不在原始模板中命名。N::hTint