为什么成员函数temporaries没有绑定到正确的类型?

时间:2009-09-17 18:05:07

标签: c++ templates

假设我们有以下基类和派生类:

#include <string>
#include <iostream>

class Car {
public:
    void Drive() { std::cout << "Baby, can I drive your car?" << std::endl; }
};

class Porsche : public Car {
};

..以及以下模板功能:

template <typename T, typename V>
void Function(void (T::*m1)(void), void (V::*m2)(void)) {
    std::cout << (m1 == m2) << std::endl;
}

为什么使用GCC进行编译:

int main(int argc, char** argv) {
    void (Porsche::*ptr)(void) = &Porsche::Drive;
    Function(ptr, ptr);
    return 0;
}

......但不是吗?

int main(int argc, char** argv) {
    void (Porsche::*ptr)(void) = &Porsche::Drive;
    Function(&Porsche::Drive, ptr);
    return 0;
}

2 个答案:

答案 0 :(得分:7)

int main(int argc, char** argv) {
    void (Porsche::*ptr)(void) = &Porsche::Drive;
    Function(&Porsche::Drive, ptr);
    return 0;
}

ptr的类型为void (Porsche::*)(),但&Porsche::Drive的类型为void (Car::*)()(因为该成员位于Car,而不是Porsche) 。因此,调用的函数将这两个成员指针与这些类型进行比较,标准说明

  

此外,可以比较指向成员的指针,或指向成员的指针和空指针常量。执行成员转换(4.11)和资格转换(4.4)的指针以使它们成为通用类型。如果一个操作数是空指针常量,则公共类型是另一个操作数的类型。否则,公共类型是指向成员类型的指针,类似于(4.4)与其中一个操作数的类型,具有cv-限定签名(4.4),它是操作数类型的cv限定签名的并集。

4.11描述了从void (Base::*)()void (Derived::*)()的隐式标准转换。因此,比较将找到共同类型void (Porsche::*)()。对于类型为Porsche的对象,两个成员指针都将引用相同的函数(即Car::Drive) - 因此比较将产生真。 comeau web compiler遵循此解释并编译您的代码。

答案 1 :(得分:1)

使用g ++ 4.0.1,您提供的示例编译正常,但在处理不同类型的成员函数指针的比较时存在问题(即使比较的元素是虚方法。

struct base
{
   void f() {}
   virtual void g() {}
};
struct derived : public base
{
   void f() {}
   virtual void g() {}
};
template <typename T, typename U>
bool cmp( void (T::*lhs)(), void (U::*rhs)() ) {
   return lhs == rhs;
}
int main()
{
   void (base::*bp)() = &base::f;
   void (base::*bvp)() = &base::g;

   cmp( bp, &base::f );  // compiles
   cmp( bvp, &base::g ); // compiles

   void (derived::*dp)() = &derived::f;
   void (derived::*dvp)() = &derived::g;

   cmp( dp, &derived::f );  // compiles
   cmp( dvp, &derived::g ); // compiles

   cmp( bp, dp );   // fails to compile
   cmp( bvp, dvp ); // fails to compile
}

现在,我已经使用comeau在线编译器进行了相同的测试,整个代码编译得很好。我不能马上告诉你什么是标准行为。我将不得不浏览一段时间的标准。

编辑:我猜不是,litb已经做了。