为什么直接使用条件运算符而不使用条件运算符进行分配时,该功能指针分配为何起作用?

时间:2019-07-04 08:56:13

标签: c++ function pointers overloading

(此示例中未使用#include,在带有g ++,选项-O0 -g3 -Wall -c -fmessage-length = 0的MacOS10.14,Eclipse IDE上编译)

假设此变量声明:

int (*fun)(int);

无法通过“ std :: toupper和std :: tolower的无效重载”进行编译。

fun = (1 ? std::toupper : std::tolower);   // ERROR, invalid overload

这样编译就可以了:

if (1) {
    fun = std::toupper;   // OK
}
else {
    fun = std::tolower;   // OK
}

3 个答案:

答案 0 :(得分:29)

std::toupper12)和std::tolower12)超载。在为conditional operator确定它们之间的通用类型时(在分配给chr2fun之前),不能确定应该使用哪种重载。

您可以使用static_cast来指定应考虑的哪一个。 (通常,首先迫使overload resolution发生,然后确定通用类型的麻烦就消失了。)

  

static_cast也可用于通过将函数到指针转换为特定类型来消除函数重载的歧义

例如

chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper) 
                               : static_cast<int(*)(int)>(std::tolower));

对于第二种情况,chr2fun被直接分配; chr2fun的类型是显式的,并且将在overload resolution中选择正确的重载。

(重点是我的)

  

在所有这些上下文中,从重载集中选择的函数是其类型与目标期望的指向函数,指向函数的引用或指向成员函数类型的指针相匹配的函数:正在初始化的对象或引用,< strong>作业的左侧,函数或运算符参数,函数的返回类型,强制类型转换的目标类型或模板参数的类型。

答案 1 :(得分:11)

在第一种情况下,编译器在进入分配之前就不愿做。简化表达:

(true ? std::toupper : std::tolower)

如果存在toupper / tolower的多个重载,将无法编译。这是因为三元运算符的返回类型必须仅基于2nd和3rd参数的类型来建立,而不必查看使用其结果的上下文。

足够有趣,即使其中一个参数不是重载函数,仍然不够。造成这种情况的原因不太明显,与overload resolution 1 规则及其适用位置有关。强制转换恰好是触发它的七种可能性之一,而确定目标三元运算符本身的类型不是。

在直接分配的情况下,分配的rhs必须符合lhs,因此没有歧义。

无论哪种方式,如@Caleth所指出的,根据16.5.4.2.1.6,此代码具有未指定的行为。


1 C ++参考的C ++ Standard段落不正确。 [over.over]实际上是12.4。

答案 2 :(得分:0)

snippet可以在gcc 9.1上正常编译

#include <cctype>

int chr2fun(bool str2modus) {
    const bool STR2UP = true;
    int (*chr2fun)(int);

    if (str2modus == STR2UP) {
        chr2fun = std::toupper;
    } else {
        chr2fun = std::tolower;
    }
    chr2fun = (str2modus == STR2UP ? std::toupper : std::tolower);
}

在哪个平台和哪个编译器上会收到错误消息?