代码之家  ›  专栏  ›  技术社区  ›  Barry

将指向base成员的指针转换为指向派生

  •  15
  • Barry  · 技术社区  · 7 年前

    一个简化的例子 a recent blog post

    struct B { void f(); };
    struct D : B { };
    
    constexpr auto as_d = static_cast<void(D::*)()>(&D::f); // (1)
    
    template <void (D::*)()>
    struct X { };
    
    X<as_d> x; // (2)
    

    gcc、clang和MSVC都接受 as_d (1) . 海合会和克朗都拒绝宣布 x 标记 (2)

    gcc和clang的错误消息都表明他们知道这一点 作为\u d 是指向的成员的指针 B . 叮当声:

    <source>:9:3 :错误:抱歉,指向成员类型的指针的非类型模板参数 void (D::*)() 指的是会员 B::f

    合同通用条款:

    <source>:9:7 :错误: void (D::*)(){((void (D::*)())B::f), 0} 不是类型的有效模板参数

    谁是对的?如果是gcc/clang,我们违反的规则是什么?看起来确实是这样 作为\u d 是类型的转换常量表达式 无效(D::*)()

    1 回复  |  直到 7 年前
        1
  •  6
  •   Barry    7 年前

    好吧,结果很有趣。就语言而言,这个程序是有效的- as_d

    然而 Itanium C++ ABI does not specify a mangling 对于这种情况(即,具有非类型模板参数,其类型是指向派生成员的指针,但其值是指向基成员的指针)。因此,针对该ABI(即clang和gcc)的编译器无法接受此代码。这就解释了为什么clang的错误是“对不起,还没有”,而不是“不,坏!”

    另一方面,其他abi没有这样的损坏问题,因此MSVC和ICC都能够很好地编译程序。