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

ㄈㄟㄈ*_*ㄟㄈㄟ 28 c++ pointers overloading function

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

假设此变量声明:

int (*fun)(int);
Run Code Online (Sandbox Code Playgroud)

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

fun = (1 ? std::toupper : std::tolower);   // ERROR, invalid overload
Run Code Online (Sandbox Code Playgroud)

这样编译就可以了:

if (1) {
    fun = std::toupper;   // OK
}
else {
    fun = std::tolower;   // OK
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 29

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

您可以static_cast用来指定应考虑的哪一个。(通常,首先要强制执行重载解析,然后再消除确定通用类型的麻烦。)

static_cast 还可以通过执行将函数到指针的转换为特定类型来消除函数重载的歧义

例如

chr2fun = (str2modus == STR2UP ? static_cast<int(*)(int)>(std::toupper) 
                               : static_cast<int(*)(int)>(std::tolower));
Run Code Online (Sandbox Code Playgroud)

对于第二种情况,chr2fun直接分配;的类型chr2fun是显式的,并且将在过载解析中选择正确的过

(强调我的)

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

  • @BartekBanachewicz通常,“可选地放置在全局名称空间中”的原因是因为不同的实际实现会做不同的事情,并且要求强制或禁止这样做会在某些实现上投入过多的实现工作。(我有点设定,C ++ 98试图坚持使用带有某些标头的“ std :: only”,并且几乎所有实现都继续执行并忽略了它们,因为这样很难与现有的C库集成。) (2认同)

Bar*_*icz 12

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

(true ? std::toupper : std::tolower)
Run Code Online (Sandbox Code Playgroud)

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

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

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

就像@Caleth指出的那样,按照16.5.4.2.1.6的任何一种方式,此代码都具有未指定的行为。


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

  • @phh由于它们的重载,它们具有相同的* set *集。应该使用哪个匹配对来确定`?:`的最终类型? (2认同)