为什么允许使用不同的转换函数将 int 和 const int 进行转换?

26

为什么以下代码可以在C++中编译通过?

#include<iostream>
using namespace std;

class mytest
{
public:    
    operator int()
    {
        return 10;
    }

    operator  const int()
    {
        return 5;
    }
};

int main()
{
    mytest mt;
    //int x = mt;    //ERROR ambigious 
    //const int x = mt; //ERROR ambigious
}
为什么允许编译不同版本 (基于constness) 的转换运算符,当它们的使用总是导致模棱两可?有人能澄清我在这里缺少什么吗?

2
猜测:似乎没有人在意过制作一个稍微有用与完全无用情况的列表,所以标准中没有相应的规则。例如,将其设为const int() volatile可能会使其再次变得有用。或许。 - Bo Persson
没有规定禁止无用的声明。试图排除所有无用的结构是语言设计的一个非常糟糕的策略。 - curiousguy
编译器会因为只有返回类型不同的函数而抛出错误...这只是该情况的特例...所以应该报错。 - code707
根据定义,函数不能仅在返回类型上有所不同,编译器会因为同一函数的两个不同声明而发出警告。 - curiousguy
4个回答

18

对于转换,它们是含糊的;但您可以明确地称呼它们。例如:

int x = mt.operator int();
const int x = mt.operator const int();

你有想法在哪些情况下这可能是有意义的吗? - Wolf
1
在现实世界中,我想不出任何一个。 - songyuanyao
也许是用于绑定成员函数指针?我手头没有语法... - Wolf
@Wolf 是的,你可以这样做,但我仍然认为这不是转换函数的适当用法。 - songyuanyao
1
我认为这应该在标准中被禁止。 - code707
18
请自由地撰写提案,列出不允许使用const限定符的类型,或者解释为什么任何类型(包括复杂的用户定义类型)都不应该使用const限定符。 显然,没有其他人对此感到足够强烈,去完成这项工作,但你可以成为那个人! - Useless

5

我认为,严格地说,即使对于const来说这可能没有太多意义,这也是合法的。

函数声明和函数类型之间有区别,它们具有不同的约束条件。

函数声明不能仅在返回类型或(自C++17以来)异常声明方面有所不同。然而,就我所知,对于函数类型并未提到过这样的事情。

标准[class.conv.fct]将转换函数描述为具有这样或那样的形式(列出了三种替代方案),它们都不像普通函数声明,特别是它们明显没有返回类型。

它确实说明了,函数类型是"不带参数并返回转换类型标识符的函数",但从未提到过转换函数声明具有返回类型。相反,所列出的三种替代方案明显没有返回类型。

由于转换函数在其声明中没有返回类型......,因此它不会发生冲突。所以,我猜,在最严格、最追求正确的意义下,即使它没有什么意义,它也是合法的。

如果你考虑一下,它在某种程度上不得不是合法的。一个类很可能有多个转换函数转换为不同的类型(不仅仅是通过const区分)。这样的代码确实存在,有时沿这条路走会很有意义。
例如,你可以拥有一个类File,将其转换为string(文件名)或handle_t(操作系统句柄),以便在使用一些操作系统特定或奇特功能的情况下使用包装类本身不直接支持的函数(例如writevteeepoll)。这肯定是你期望能够正常工作的东西!
然而,如果我们将转换函数视为"普通函数",那么它们只能通过返回类型进行区分,这将使声明非法。所以...那行不通。


转换函数没有返回类型--这是一个有趣的观点,它教导我们不要把转换运算符仅仅看作一种函数,而是像构造函数一样,也没有返回类型但可以用来获取对象。这也是一个可接受的答案 :) - Wolf

4
为什么允许编译不同版本的转换运算符(基于constness),即使它们的使用总是导致歧义?这通常没有意义(除了高度人工的用例),编译器可以向您发出警告:
prog.cc:12:25: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
     operator  const int()
                         ^

你能添加这样的用例吗? - Wolf
@Wolf 请参考songyuanyao的回答。使用案例是为了展示您可以通过能够单独调用它们来区分它们之间的差异。这就是为什么我认为高度人工,没有实际用途。 - Jodocus
由于明显的原因,没有人可能这样做,因此引入一种不允许它的措辞变化是没有意义的。无论如何,那是我的两分钱。 - StoryTeller - Unslander Monica
考虑一些模板代码,其中您不直接获得“int”和“const int”,而是获得更复杂的类型计算,这些计算恰好为某些模板参数输出这些类型。 - T.C.
@T.C. 可能是这样,但 code707 的代码示例并没有介绍任何模板的概念。 - Jodocus
不完全相同,但签名略有不同:operator const int&()有些道理;如果你知道可能经常发生的转换并想要缓存它(好吧,也许不是一个int,而是一个更大的对象);如果由于某种未知原因移动它很昂贵...虽然我在现实世界中没有见过这样的用法。 - UKMonkey

1
我得出结论:不能显式地编写只有返回值constness不同的对话操作符。对于编译过程来说,明确禁止这样做是太过昂贵的。请记住,仅由其返回类型不同的(成员)函数。
class mytest
{
    int f();
    const int f();
};

被禁止的内容:

错误:‘const int mytest::f()’无法重载

只是转换运算符以 operator 开头,这使得它们与其他函数不同。


7
类型是转换函数名称的一部分,可以这么说。实际上它不是两个仅有返回类型不同的函数重载,而是两个不同的函数。 - StoryTeller - Unslander Monica
@StoryTeller,把这个作为另一个答案加进去怎么样?到目前为止给出的答案并不是很令人满意... - Wolf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接