在 class 范围内将指针传递给 constexpr 函数时是否滥用推断父模板的参数
Is it abuse to deduce parameters of parent template when passing pointer to constexpr function in the scope of a class
我得到的最小例子有点复杂:
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>{};
}
[gcc] compiles the code without any problem, [clang] 抱怨匹配 Parent
与 Kid
问题:
prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid'
constexpr int operator*(A, Parent<N>*) { return N; }
当我们稍微更改代码时变得更荒谬:
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>{};
}
[clang] 也会编译代码。所以...这是一个错误还是我开始发疯了?
Clang 遵守法律规定。是的,Kid
源自 Parent
。但是这种关系只有在 Kid
是一个完全定义的类型时才能建立。还有,[class.mem]/6:
A class is considered a completely-defined object type ([basic.types])
(or complete type) at the closing } of the class-specifier. Within the
class member-specification, the class is regarded as complete within
function bodies, default arguments, noexcept-specifiers, and default
member initializers (including such things in nested classes).
Otherwise it is regarded as incomplete within its own class
member-specification.
我们在我突出显示的 "otherwise" 部分。即使我们处理的是指针,class 还没有被定义为指针转换是有效的。 GCC 过于宽松。
我得到的最小例子有点复杂:
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>{};
}
[gcc] compiles the code without any problem, [clang] 抱怨匹配 Parent
与 Kid
问题:
prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid'
constexpr int operator*(A, Parent<N>*) { return N; }
当我们稍微更改代码时变得更荒谬:
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>{};
}
[clang] 也会编译代码。所以...这是一个错误还是我开始发疯了?
Clang 遵守法律规定。是的,Kid
源自 Parent
。但是这种关系只有在 Kid
是一个完全定义的类型时才能建立。还有,[class.mem]/6:
A class is considered a completely-defined object type ([basic.types]) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, noexcept-specifiers, and default member initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.
我们在我突出显示的 "otherwise" 部分。即使我们处理的是指针,class 还没有被定义为指针转换是有效的。 GCC 过于宽松。