模板实例化不"do inheritance"

Template instantiation does not "do inheritance"

本文关键字:do inheritance 实例化      更新时间:2023-10-16

标题引用自SO答案。讨论了使用SFINAE检测具有给定签名的成员函数的存在性,并指出了该方法在处理继承成员函数时在接受答案中的一个失败之处。特别是,给出的解释如下

如果你还不知道这个问题,那么看看标题中std::shared_ptr<T>的定义就会明白。在该实现中,std::shared_ptr<T>是从继承operator*() const的基类派生的。因此,构成为U = std::shared_ptr<T>"查找"运算符的模板实例化SFINAE<U, &U::operator*>不会发生,因为std::shared_ptr<T>本身没有operator*(),模板实例化也没有"继承"。

这个障碍并不影响众所周知的SFINAE方法,该方法使用"the sizeof()Trick",仅用于检测T是否具有某个成员函数mf(参见例如这个答案和注释)。

使用答案中的术语,使用T::mf作为模板参数实例化类型与让编译器通过模板函数参数推导来确定类型之间有什么区别?"模板实例化不做继承"是什么意思?最后,为什么这不影响简单地检查成员的存在,就像这里一样?

最小化示例:

struct A {
    void a() const;
};
struct B : A {};
template<typename U, void (U::*)() const> struct SFINAE {};
template<typename U> void Test(SFINAE<U, &U::a>*) { }
int main(void)
{
    Test<B>(0); // doesn't compile
    return 0;
}

演示。

问题是,当B::aA继承时,&B::a的类型实际上是"指向A成员的指针",并且,虽然通常指向基成员的指针可以隐式转换为指向派生成员的指针,但根据§14.3.2[temp.arg.notype]/p5:,这种转换不适用于非类型模板参数

对用作非类型模板参数。如果非类型模板参数不能转换为相应模板参数的类型则该程序是格式错误的。

  • […]
  • 对于指向成员函数的指针类型的非类型模板参数,如果模板参数的类型为std::nullptr_t应用空成员指针转换(4.11);否则,否转换适用。如果模板参数表示重载成员函数,则选择匹配的成员函数来自集合(13.4)