class 模板何时依赖不完整类型作为模板参数实例化?

When is a class template depending on a incomplete type as a template argument instantiated?

class I;

template<class T>
struct P
{
    T t;
};

template<class T>
struct F
{
    operator bool() {return false;}
};


int main()
{
    int a = F<P<I>>();
    int b = !F<P<I>>();
    int c = int(F<P<I>>());
    int d = !int(F<P<I>>());
}

上面的初始化器中的计算是否格式正确?为什么或者为什么不?标准中的哪些规则规定了行为?

只有在需要完整类型或影响给定上下文中的语义时,才会实例化特化。 [temp.inst]/2

因此默认行为是在不必要时不进行任何隐式实例化。

在您显示的所有情况下,需要实例化 F 的特化,因为 T() 需要 T 才能完成。但是F<P<I>>的实例化中没有任何东西需要P<I>来完成,所以不会用它来实例化。

None 到 int 的转换需要 P<I> 完成,因此 ac 和 [=19= 的初始化] 根本不会导致 P<I> 的任何实例化,它们是 well-formed.

但是,对于 b,情况有点不同。为了确定要调用哪个 operator! 重载,已完成 operator! 的非限定名称查找和 argument-dependent 名称查找。

Argument-dependent 查找在与类型 F<P<I>>.

相关的多个范围内查找 operator! 声明

首先,对于F本身,它包括F的class作用域和封闭的命名空间作用域,即全局作用域。但是,其次,它还在类型的模板参数中包括 class- 和封闭类型的命名空间范围,这意味着它也包括 P<I> 的 class 范围。

为了判断P<I>中是否存在operator!重载,必须对其进行实例化。在实例化 P<I> 时,声明 T t; 也被实例化为 I t;,这需要 I 完成,但事实并非如此,使得 [=21= 的初始化] ill-formed.


但是 [temp.inst]/9 允许但不要求在不需要确定重载解析结果时跳过实例化。我不确定这个权限应该解释多宽,但如果它在这里适用,那么未指定 P<I> 的实例化是否发生 b 的初始化。