c++ 转换运算符重载、枚举、整数和字符

Posted

技术标签:

【中文标题】c++ 转换运算符重载、枚举、整数和字符【英文标题】:c++ conversion operator overloading, enums, ints and chars 【发布时间】:2011-11-18 00:56:22 【问题描述】:

当我尝试编译(使用 gcc 4.3.4)这段代码 sn-p:

enum SimpleEnum 
    ONEVALUE
;

void myFunc(int a) 


void myFunc(char ch) 


struct MyClass 
    operator int() const  return 0; ;
    operator SimpleEnum() const  return ONEVALUE; ;
;

int main(int argc, char* argv[]) 
    myFunc(MyClass());

我收到此错误:

test.cc: In function "int main(int, char**)":
test.cc:17: error: call of overloaded "myFunc(MyClass)" is ambiguous
test.cc:5: note: candidates are: void myFunc(int)
test.cc:8: note:                 void myFunc(char)

我想我(几乎)理解问题所在,即(简化了很多)即使我谈到“char”和“enum”,它们都是整数,然后重载是模棱两可的。

无论如何,我不太明白的是,如果我删除 myFunc OR 的转换运算符之一的第二个重载 MyClass em>,我没有编译错误。

由于这个问题我要更改很多旧代码(我正在将代码从旧版本的 HP-UX aCC 移植到 Linux 下的 g++ 4.3.4),我想更好地理解为了选择最好的方式修改代码。

提前感谢您的帮助。

【问题讨论】:

如果您删除转换为int,它对您有用吗?还是像其他人建议的那样从枚举到 int/char 的转换仍然模棱两可? @K-ballo:如果我删除两个转换之一,它会起作用。如果我删除“void myFunc(char ch)”,它会起作用。如果我删除“void myFunc(int a)”,我会得到(几乎)同样的错误。 我坚持认为,上面的示例没有编译,而没有“void myFunc(char ch)”编译的示例,从常识的角度来看显然是错误的,当然,违反直觉。无论如何,从您的回答中,我知道这是(丑陋的)标准,我会尊重它(也因为我别无选择)。仅供参考,我决定将显式强制转换为 int 到我的生产代码中。感谢任何回答并因此帮助我更好地理解整个事情的人。 【参考方案1】:

MyClass 的转换是不明确的,因为有一个到int 的转换和一个到枚举的转换,它本身可以隐式转换为int,两者都是同样好的转换。不过,您可以通过指定所需的转换来明确调用:

myfunc(int(MyClass()));

或者,您可能想重新考虑为什么您有一个函数具有单独的 intchar 重载,也许也可以重新设计。

【讨论】:

歧义不在enumintchar之间,它实际上在enum之间,可转换为int,用户定义转换为int。调用 yo myFunc( ONEVALUE ) 应该没问题,并且会选择 int 重载。 @K-Ballo:你说得对,我搞砸了。让我修复它。谢谢! 这两个转换运算符可能是“冲突的”这一事实对我来说很清楚,而且我可以通过明确指定要使用的转换来解决这个问题,这在我在这里发布之前得到了验证。无论如何,最让我不安的是,如果我删除 myFunc 的“char”重载,一切正常。但是 MyClass 的两次转换仍然存在,为什么我不再收到错误?我希望了解这一事实可以帮助我找到合适的解决方案(显式转换会导致代码的重大返工,因此,我试图避免它)。 @port: 如果myfunc只有一个版本,那么转换成int比较好,因为它需要no隐式转换,所以没有模棱两可。【参考方案2】:

enums are types in C++,不像 C。

enum -> charenum -> int 都有隐式转换。编译器只是不知道该选择哪一个。


编辑:尝试不同的测试后:

当自定义转换的定义 MyClass -> int 被移除时,代码编译。 这里有枚举到int 的隐式转换,因此它是编译器所青睐的,而不是char。 Test here。删除 void myFunc(int) 的定义时,编译失败。 编译器尝试从MyClass 转换为char,并发现在没有用户定义的转换运算符char() 的情况下,可以使用用户定义的int()SimpleEnum()。 Test here。当您为 MyClass 添加 char() 转换运算符时,编译失败并出现与未添加时相同的错误。 Test here.

所以我在这里得出的结论是,在您最初发布的代码中,编译器必须决定应该调用myFunc 的两个重载版本中的哪一个。 由于两种转换都是可能的:

    MyClassint 通过用户定义的转换运算符。 MyClassint 通过用户定义的转换(MyClassSimpleEnum)+ 隐式转换(SimpleEnumchar

编译器不知道使用哪一个。

【讨论】:

歧义不在enumintchar之间,它实际上在enum之间,可转换为int,用户定义转换为int。调用 yo myFunc( ONEVALUE ) 应该没问题,并且会选择 int 重载。 那为什么编译器会产生误导性的错误描述? @K-ballo:看起来它是两者的结合,看看这个:ideone.com/75Huq 确实,如果唯一的重载是 int ,那么用户定义的到 int 的转换是“更短”的路径,因此被选中。我仍然认为这段代码不应该导致编译器错误,因为在每种情况下都应该选择用户定义的到 int 的转换......我希望标准大师告诉我们代码是否合法。 @K-ballo:实际上我希望选择更短的路径(旧的 aCC 编译器会发生这种情况,因为它与当前的 C++ 标准不是最新的)【参考方案3】:

我本来希望调用 int 重载。尝试了一些编译器并得到了不同的结果。如果要删除任何内容,请将用户转换运算符删除为int,因为枚举具有到整数的标准转换。

【讨论】:

不幸的是,实际情况比我发布的示例要复杂一些:我有可以转换为 int 以便存储到 DB 并且可以转换为其他枚举的伪枚举类它们是 CORBA 枚举,以便与其他进程通信。我真的无法删除任何转换(或者我可以,然后我必须手动修复数千行代码,在数十万行代码中搜索它们)。

以上是关于c++ 转换运算符重载、枚举、整数和字符的主要内容,如果未能解决你的问题,请参考以下文章

C++运算符重载学习总结

C++之重载运算与类型转换

为枚举类重载强制转换运算符

C++ 强制转换运算符重载和多态性

重载强制转换运算符时的 C++ 歧义

赋值运算符的布尔和字符串重载 (C++)