在类的范围内传递指向constexpr函数的指针时,是否滥用推断父模板的参数

W.F*_*.F. 8 c++ language-lawyer incomplete-type constexpr template-argument-deduction

我得到的最小例子有点复杂:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static Other<A{} * ptr<Kid>{}> o;
};

int main() {
    Kid<2>{};
}
Run Code Online (Sandbox Code Playgroud)

[GCC]编译代码而没有任何问题,[铛]抱怨匹配Parent针对Kid问题:

prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid'
constexpr int operator*(A, Parent<N>*) { return N; }
Run Code Online (Sandbox Code Playgroud)

当我们稍微更改代码时更加荒谬:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static constexpr int s = A{} * ptr<Kid>{};
};

int main() {
    Other<Kid<2>::s>{};
}
Run Code Online (Sandbox Code Playgroud)

[clang]也编译代码.所以...这是一个错误还是我开始变得疯狂?

Sto*_*ica 6

Clang对法律条文是正确的.是的,Kid源于Parent.但只有Kid完全定义的类型才能建立这种关系.好吧,[class.mem]/6:

在类说明符的结束时,类被认为是完全定义的对象类型([basic.types])(或完整类型).在类成员规范中,该类在函数体,默认参数,noexcept-specifiers和默认成员初始化器(包括嵌套类中的这类事物)中被视为完整. 否则,它在其自己的类成员规范中被视为不完整.

我们强调了"其他"部分.即使我们处理指针,该类还没有被认为是指针转换有效.海湾合作委员会过于宽容.