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

发布于 2024-08-04 22:31:04 字数 540 浏览 6 评论 0原文

我在处理 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++,如果这有什么区别的话。

谢谢!

I'm having a minor issue dealing with pointers to overloaded member functions in C++. The following code compiles fine:

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;

But this doesn't compile (the compiler complains that the overloads are ambiguous):

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

Presumably this is something to do with the compiler sorting out the return value of the conditional operator separately from the function pointer type? I can work around it, but I'm interested to know how the spec says all this is supposed to work since it seems a little unintuitive and if there's some way to work around it without falling back to 5 lines of if-then-else.

I'm using MSVC++, if that makes any difference.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葬花如无物 2024-08-11 22:31:04

从第 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));

From section 13.4/1 ("Address of overloaded function," [over.over]):

A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type matches the target type required in the context. The target can be

  • an object or reference being initialized (8.5, 8.5.3),
  • the left side of an assignment (5.17),
  • a parameter of a function (5.2.2),
  • a parameter of a user-defined operator (13.5),
  • the return value of a function, operator function, or conversion (6.6.3), or
  • an explicit type conversion (5.2.3, 5.2.9, 5.4).

The overload function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed. [Note: any redundant set of parentheses surrounding the overloaded function name is ignored (5.1). ]

The target you were hoping would be selected from the above list was the first one, an object being initialized. But there's a conditional operator in the way, and conditional operators determine their types from their operands, not from any target type.

Since explicit type conversions are included in the list of targets, you can type-cast each member-pointer expression in the conditional expression separately. I'd make a typedef first:

typedef void (Foo::* float_func)(const float);
float_func func = (someCondition ? float_func(&Foo::X) : float_func(&Foo::Y));
錯遇了你 2024-08-11 22:31:04

尝试:

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

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

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

Try:

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

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

The problem is the result type of the operator trinary is determined by its arguments.
In this situation it can not determine the result type because the input types has multuiple options. It is not until the type of the trinary operator has been determined that it will attempt the assignment.

忘年祭陌 2024-08-11 22:31:04

示例:

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 才能解决重载问题。请注意,如果您注释掉重载的 float X(),则不需要这样做。

编译器似乎不够智能,无法推断三元表达式所需的返回类型(这可能是一个错误)。

Example:

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;
}

You need to cast &Foo::X immediately in order to resolve the overload. Note that if you comment out the overloaded float X(), you don't need to do so.

It looks like the compiler isn't smart enough to infer the required return type of a ternary expression (this may be a bug).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文