转换逻辑的目标是什么类型? [英] What type does the conversion logic target?

查看:57
本文介绍了转换逻辑的目标是什么类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白为什么在下面的代码中表达式 C c3 = 5 + c;尽管 5 可以像前面的语句一样转换为 C 类型,但不会被编译.

I don't understand why in the following code the expression C c3 = 5 + c; doesn't get compiled although 5 could be converted to type C as in the previous statement.

#include <iostream>

class C 
{
    int m_value;
public:
    C(int value): m_value(value) {} ;

    int get_value() { return m_value; } ; 

    C operator+(C rhs) { return C(rhs.m_value+m_value); }
};

int main()
{
    C c = 10;
    C c2 = c + 5; // Works fine. 5 is converted to type C and the operator + is called
    C c3 = 5 + c; // Not working: compiler error. Question: Why is 5 not converted to type C??

    std::cout << c.get_value() << std::endl; // output 10
    std::cout << c2.get_value() << std::endl; // output 15

}



推荐答案

这是关于为什么您建议编译器可以将左手参数隐式转换为 C 本质上会打开一堆蠕虫.实际的语言规则说,简单地说,在应用转换之前,进行名称查找——用于函数调用和对(用户声明的)运算符的调用——以找到候选集.在这一点上,还没有考虑操作数类型,但范围很好.所以第一个参数的类型确实很重要,因为用户声明的运算符只有在它的第一个参数是它被声明的(cv 限定的)类类型时才在范围内.当一个候选集已经找到,编译器然后尝试应用转换规则并对候选等进行排名.

Here's an additional remark (a bit of a "reductio ad absurdum") on why your suggestion that the compiler could implicitly convert the left hand argument to a C would, essentially, open a can of worms. The actual language rules say, simply put, that, before applying conversions, a name lookup – for function calls and calls to (user-declared) operators – is done to find a candidate set. At this point, the operand types are not yet considered, but the scope very well is. So the type of the first argument does matter insofar as a user-declared operator is only in scope if its first argument is of the (cv-qualified) class type it is declared in. When a candidate set has been found, the compiler then tries to apply the conversion rules and ranks the candidates etc.

(因此,您的问题有点误导,因为在您的示例中,我们甚至没有涉及转换逻辑,而是名称解析已经为空.)

(Your question is therefore a bit misleading because in your example, we don't even get to the conversion logic, instead name resolution already comes up empty.)

现在,想象一下我们可以简单地改变语言,说第一个参数也可以在名称解析之前被转换.这里需要一点手动操作,因为这意味着我们必须进行转换,查找名称,然后再次进行转换,因此在实践中这将如何工作当然不清楚.无论如何,看看这个例子:

Now, imagine we could simply change the language to say that the first argument can also be converted, prior to name resolution. A little bit of handwaving is required here, because this means we have to do conversions, look up names, and then do conversions again, so how this would work in practice is certainly unclear. Anyway, look at this example then:

struct B;
struct A
{
    A(int);
    A operator +(B) const;
};
struct B
{
    B(int);
    B operator +(B) const;
};

现在,1 + B{3} 应该怎么做?显然,它可以转换为B{1} + B{3}.但谁又能说我们不能用 A{1} + B{3} 代替呢?为什么 B 的构造函数比 A 的构造函数更受欢迎?当然,我们可以争辩说 B 是首选,因为,看看 B{...}+B{...} 是多么漂亮和对称(好吧,我有点开玩笑).或者,如果程序包含这样的歧义,我们可以采取更安全的方式说程序格式错误.但是还有更多的极端情况需要考虑,例如如果 B 的构造函数是 explicit - 编译器(仍然或新)是否应该出错,或者它是否应该静默切换到可用的隐式转换到 A?

Now, what should 1 + B{3} do? Apparently, it could be transformed to B{1} + B{3}. But who's to say we couldn't do A{1} + B{3} instead? Why would B's constructor be preferred over A's? Of course, we could argue that either B is to be preferred, because, look at how nice and symmetric B{...}+B{...} is (ok, I'm being slightly facetious). Or we could take the safer route of saying that the program is ill-formed if it contains such an ambiguity. But there are a lot more corner cases to consider, e.g. what if B's constructor was made explicit – should the compiler (still or newly) error out, or should it silently switch to the usable implicit conversion to A?

另一个不明显的问题是哪些类型应该考虑在哪些范围(例如命名空间)中?如果您在例如使用 operator + 肯定会令人惊讶全局命名空间范围,编译器会挖掘出某种类型__gnucxx::__internal::__cogwheels::__do_something_impl,隐式地将一个操作数转换为它,然后对其执行操作.

Another non-obvious point is which types in which scopes (e.g. namespaces) should be considered? It would certainly be surprising if you use operator + in e.g. global namespace scope, and the compiler would dig out some type __gnucxx::__internal::__cogwheels::__do_something_impl, implcitly convert an operand to it, and then perform an operation on that.

还要注意,即使可以以合理和干净的方式指定此功能,也可能会产生相当大的编译时成本(实际上,重载解析已经是编译 C++ 时最大的成本之一,也是原因之一为什么编译 C++ 代码比编​​译 C 花费的时间长很多).

Also note that this feature even if it can be specified in a reasonable and clean manner, could have quite a compile-time cost (in fact, overload resolution is already one of the biggests costs when compiling C++ and one of the reasons why compiling C++ code can take a lot longer than compiling C).

TL;博士:

  • 有一些棘手的极端情况.
  • 收益微乎其微(为什么不像其他人指出的那样使这些运算符成为免费功能)?
  • 关于如何将其标准化的讨论肯定会很长.

这篇关于转换逻辑的目标是什么类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆