在c++ 20中什么是声明可达的?



§10.4/3详细给出了decl-reachable的所有可能情况。然而,我不能完全理解它。考虑§10.4/6中描述的例子:

Source file "foo.h":
namespace N {
struct X {};
int d();
int e();
inline int f(X, int = d()) { return e(); }
int g(X);
int h(X);
}
Module M interface:
module;
#include "foo.h"
export module M;
template<typename T> int use_f() {
N::X x;                       // N​::​X, N, and ​::​ are decl-reachable from use_­f
return f(x, 123);             // N​::​f is decl-reachable from use_­f,
// N​::​e is indirectly decl-reachable from use_­f
//   because it is decl-reachable from N​::​f, and
// N​::​d is decl-reachable from use_­f
//   because it is decl-reachable from N​::​f
//   even though it is not used in this call
}
template<typename T> int use_g() {
N::X x;                       // N​::​X, N, and ​::​ are decl-reachable from use_­g
return g((T(), x));           // N​::​g is not decl-reachable from use_­g
}
template<typename T> int use_h() {
N::X x;                       // N​::​X, N, and ​::​ are decl-reachable from use_­h
return h((T(), x));           // N​::​h is not decl-reachable from use_­h, but
// N​::​h is decl-reachable from use_­h<int>
}
int k = use_h<int>();
// use_­h<int> is decl-reachable from k, so
// N​::​h is decl-reachable from k
Module M implementation:
module M;
int a = use_f<int>();           // OK
int b = use_g<int>();           // error: no viable function for call to g;
// g is not decl-reachable from purview of
// module M's interface, so is discarded
int c = use_h<int>();           // OK

为什么N​::​g不能从use_­g声明可达?为什么N​::​h不能从use_­h读出可达,而N​::​h可以从use_­h<int>读出可达?为什么10.4/(3.2)或10.4/(3.3)不适用于他们?

N::f是decl-reachable fromuse_f,由于规则10.4.3.2.

在确定N::g是否可以从use_g到达时,我们发现10.4.3.2和10.4.3.3都不适用。

  • 10.4.3.2不适用,因为g((T(), x))是一个依赖调用,因此,在声明模板use_g时,还不能确定调用实际命名的函数是哪个。(这将在use_g实例化时确定,但在这种情况下,它可能只意味着N::g可以从use_g的特定专门化访问,而不是模板use_g本身。)
  • 10.4.3.3指示我们考虑对g的假设调用,其中每个类型相关的参数都被没有关联名称空间或实体的类型表达式替换。因此,例如,我们可以用0替换(T(), x),给出假设的调用g(0)。这不会在名称查找阶段找到N::g,因此它不会使N::gdecl可达。

由于类似的原因,N::h不能从use_h声明可达。

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

最新更新