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

条件运算符无法解析重载的成员函数指针

  •  5
  • Peter  · 技术社区  · 15 年前

    我有一个小问题处理C++中重载成员函数的指针。以下代码编译良好:

    class Foo {
    public:
        float X() const;
        void X(const float x);
        float Y() const;
        void Y(const float y);
    };
    
    void (Foo::*func)(const float) = &Foo::X;
    

    但这不会编译(编译器抱怨重载不明确):

    void (Foo::*func)(const float) = (someCondition ? &Foo::X : &Foo::Y);
    

    可能这与编译器将条件运算符的返回值与函数指针类型分开排序有关?我可以解决这个问题,但是我很感兴趣知道规范怎么说,所有这些都应该是有效的,因为它似乎有点不具说服力,如果有什么方法可以解决这个问题,而不必返回到5行if-then-else。

    我用的是MSVC++,如果有什么区别的话。

    谢谢!

    3 回复  |  直到 15 年前
        1
  •  7
  •   Rob Kennedy    15 年前

    来自第13.4/1节(“重载函数的地址,”[over.over]):

    没有参数的重载函数名的使用在某些上下文中解析为函数、指向函数的指针或指向重载集中特定函数的成员函数的指针。函数模板名称被认为是在这种上下文中命名一组重载函数的名称。所选函数的类型与上下文中所需的目标类型匹配。目标可以是

    • 正在初始化的对象或引用(8.5、8.5.3),
    • 任务的左侧(5.17),
    • 函数(5.2.2)的参数,
    • 用户定义的运算符(13.5)的参数,
    • 函数、运算符函数或转换的返回值(6.6.3),或
    • 显式类型转换(5.2.3、5.2.9、5.4)。

    重载函数名前面可以是 & 操作员。在所列上下文之外的上下文中,不能使用没有参数的重载函数名。[ 注: 忽略重载函数名周围的任何多余括号集(5.1)。]

    这个 目标 您希望从上面的列表中选择第一个,一个正在初始化的对象。但是这里有一个条件运算符,条件运算符从其操作数(而不是任何目标类型)确定其类型。

    由于目标列表中包含显式类型转换,因此可以在条件表达式中分别键入强制转换每个成员指针表达式。我先做一个typedef:

    typedef void (Foo::* float_func)(const float);
    float_func func = (someCondition ? float_func(&Foo::X) : float_func(&Foo::Y));
    
        2
  •  1
  •   Loki Astari    15 年前

    尝试:

        void (Foo::*func1)(const float) = &Foo::X;
        void (Foo::*func2)(const float) = &Foo::Y;
    
        void (Foo::*func3)(const float) = (someCondition ? func1:func2);
    

    问题是,三元运算符的结果类型由其参数决定。
    在这种情况下,它无法确定结果类型,因为输入类型具有多个选项。直到确定三元运算符的类型后,才会尝试赋值。

        3
  •  1
  •   Michael Burr    15 年前

    例子:

    class Foo {
    public:
        void X(float x) {}
        void Y(float y)  {}
        float X() const;
    };
    typedef void (Foo::*Fff)(float);
    Fff func = &Foo::X;
    Fff func2 = true ? (Fff)&Foo::X : (Fff)&Foo::Y;
    
    int main(){
        return 0;
    }
    

    您需要立即强制转换&foo::x以解决过载问题。请注意,如果您注释掉重载的floatX(),则不需要这样做。

    看起来编译器不够聪明,无法推断出三元表达式所需的返回类型(这可能是一个错误)。