(此示例中未使用#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
}
答案 0 :(得分:29)
std::toupper
(1和2)和std::tolower
(1和2)超载。在为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);
}
在哪个平台和哪个编译器上会收到错误消息?