通过初始标准转换序列区分用户定义的转换序列 [英] Distinguishing between user-defined conversion sequences by the initial standard conversion sequence

查看:169
本文介绍了通过初始标准转换序列区分用户定义的转换序列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

标准似乎提供了两个规则,用于区分涉及用户定义的转换运算符的隐式转换序列:

The standard appears to provide two rules for distinguishing between implicit conversion sequences that involve user-defined conversion operators:


c ++ 11

[...]是一个比另一个可行函数更好的函数
F2 if [...]

[...] a viable function F1 is defined to be a better function than another viable function F2 if [...]


  • 定义的转换(见8.5,13.3.1.5和13.3.1.6)和从返回类型F1到目标类型(即正在初始化的
    实体的类型)的
    标准转换序列是比标准转换序列更好的转换顺序从
    F2的返回类型到目标类型。

3 - 相同形式的两个隐式转换序列是无法区分的转换序列,除非
中的一个符合以下规则应用:[...]

3 - Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies: [...]


  • 用户定义的转换序列U1比另一个用户定义的转换序列U2包含相同的用户定义的转换函数或构造函数或聚合
    初始化,U1的第二个标准转换序列优于U2的第二个标准
    转换序列。


    • User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function or constructor or aggregate initialization and the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2.

    根据我的理解,13.3.3允许编译器区分不同的用户定义的转换操作符,而13.3.3.2允许编译器区分每个在其参数中需要用户定义的转换的不同的函数(某些函数的重载 f )请参阅我的侧栏以给定以下代码(在GCC 4.3中),为什么将引用的转换称为两次?)。

    As I understand it, 13.3.3 allows the compiler to distinguish between different user-defined conversion operators, while 13.3.3.2 allows the compiler to distinguish between different functions (overloads of some function f) that each require a user-defined conversion in their arguments (see my sidebar to Given the following code (in GCC 4.3) , why is the conversion to reference called twice?).

    可以区分用户定义的转换序列的规则? http://stackoverflow.com/a/1384044/567292 上的答案表明13.3.3.2:3可以区分基于隐式对象参数(转换运算符)的cv限定或者单个非默认参数到构造函数或聚合初始化的cv限定的用户定义的转换序列,但是我不知道如何可以相关给定这将需要在相应的用户定义的转换序列的第一标准转换序列之间进行比较,该标准没有提及。

    Are there any other rules that can distinguish between user-defined conversion sequences? The answer at http://stackoverflow.com/a/1384044/567292 indicates that 13.3.3.2:3 can distinguish between user-defined conversion sequences based on the cv-qualification of the implicit object parameter (to a conversion operator) or of the single non-default parameter to a constructor or aggregate initialisation, but I don't see how that can be relevant given that that would require comparison between the first standard conversion sequences of the respective user-defined conversion sequences, which the standard doesn't appear to mention.

    假设S1优于S2,其中S1是U1的第一个标准转换序列,S2是U2的第一个标准转换序列,那么U1是否优于U2?换句话说,这个代码是否正确?

    Supposing that S1 is better than S2, where S1 is the first standard conversion sequence of U1 and S2 is the first standard conversion sequence of U2, does it follow that U1 is better than U2? In other words, is this code well-formed?

    struct A {
        operator int();
        operator char() const;
    } a;
    void foo(double);
    int main() {
        foo(a);
    }
    

    g ++ (4.5.1), Clang (3.0)和 Comeau (4.3.10.1)接受它,喜欢非const限定的 A :: operator int(),但我希望它被拒绝为含糊不清,从而不合格。这是标准中还是在我的理解的缺陷?

    g++ (4.5.1), Clang (3.0) and Comeau (4.3.10.1) accept it, preferring the non-const-qualified A::operator int(), but I'd expect it to be rejected as ambiguous and thus ill-formed. Is this a deficiency in the standard or in my understanding of it?

    推荐答案

    这里的诀窍是从类类型转换,非类类型实际上不会将任何用户定义的转换排序为隐式转换序列。

    The trick here is that converting from a class type to a non-class type doesn't actually rank any user-defined conversions as implicit conversion sequences.

    struct A {
        operator int();
        operator char() const;
    } a;
    void foo(double);
    int main() {
        foo(a);
    }
    

    在表达式 foo(a) foo 显然命名一个非重载非成员函数。调用需要使用单个表达式 a double 类型的函数参数进行复制初始化(8.5p14)它是类类型 A

    In the expression foo(a), foo obviously names a non-overloaded non-member function. The call requires copy-initializing (8.5p14) the function parameter, of type double, using the single expression a, which is an lvalue of class type A.

    由于目标类型 double 不是cv限定的类类型,但源类型 A 是,候选函数由第13.3.1.5节定义, S = A T = double 。仅考虑类 A 中的转换函数和 A 的任何基类。如果:

    Since the destination type double is not a cv-qualified class type but the source type A is, the candidate functions are defined by section 13.3.1.5, with S=A and T=double. Only conversion functions in class A and any base classes of A are considered. A conversion function is in the set of candidates if:


    • 在类 A

    • 不是显式(因为上下文是复制初始化)和

    • 标准转换序列可以将函数的返回类型(不包括任何引用限定符)转换为目标类型 double

    • It is not hidden in class A, and
    • It is not explicit (since the context is copy-initialization), and
    • A standard conversion sequence can convert the function's return type (not including any reference qualifiers) to the destination type double.

    好,两个转换函数都合格,所以候选函数是

    Okay, both conversion functions qualify, so the candidate functions are

    A::operator int();        // F1
    A::operator char() const; // F2
    

    使用13.3.1p4中的规则,每个函数都将隐式对象参数作为唯一东西在其参数列表中。 F1 的参数列表为(对 A )的引用值和 F2 的参数列表是(对于 const A )的值。

    Using the rules from 13.3.1p4, each function has the implicit object parameter as the only thing in its parameter list. F1's parameter list is "(lvalue reference to A)" and F2's parameter list is "(lvalue reference to const A)".

    检查功能是否可行(13.3.2)。每个函数在其参数列表中有一个类型,并且有一个参数。每个参数/参数对是否有隐式转换序列?当然:

    Next we check that the functions are viable (13.3.2). Each function has one type in its parameter list, and there is one argument. Is there an implicit conversion sequence for each argument/parameter pair? Sure:


    • ICS1(F1):绑定隐式对象参数引用 A )到表达式 a (类型的左值 A )。
    • ICS1(F2):绑定隐式对象参数(类型lvalue引用 const A $> )到表达式 a (类型的左值 A $ b
    • ICS1(F1): Bind the implicit object parameter (type lvalue reference to A) to expression a (lvalue of type A).
    • ICS1(F2): Bind the implicit object parameter (type lvalue reference to const A) to expression a (lvalue of type A).

    由于没有派生到基础的转换,这些引用绑定被认为是身份转换的特殊情况(13.3.3.1.4p1)。 Yup,这两个函数都是可行的。

    Since there's no derived-to-base conversion going on, these reference bindings are considered special cases of the identity conversion (13.3.3.1.4p1). Yup, both functions are viable.

    现在我们要确定一个隐式转换序列是否比另一个更好。这属于13.3.3.2p3中的大列表中的第五个子项:它们都是除了顶级cv限定符之外的相同类型的引用绑定。由于 ICS1(F2)的引用类型比 ICS1(F1)的引用类型更加cv限定, ICS1(F1)优于 ICS1(F2)

    Now we have to determine if one implicit conversion sequence is better than the other. This falls under the fifth sub-item in the big list in 13.3.3.2p3: both are reference bindings to the same type except for top-level cv-qualifiers. Since the referenced type for ICS1(F2) is more cv-qualified than the referenced type for ICS1(F1), ICS1(F1) is better than ICS1(F2).

    因此, F1 A :: operator int()是最可行的函数。并且没有用户定义的转换(具有由SCS +(转换构造函数或转换函数)+ SCS组成的ICS类型的严格定义)甚至被比较。

    Therefore F1, or A::operator int(), is the most viable function. And no user-defined conversions (with the strict definition of a type of ICS composed of SCS + (converting constructor or conversion function) + SCS) were even to be compared.

    现在如果 foo 重载,则需要比较参数 a 上的用户定义转换。那么用户定义的转换(identity + A :: operator int() + int double )将与其他隐式转换序列进行比较。

    Now if foo were overloaded, user-defined conversions on the argument a would need to be compared. So then the user-defined conversion (identity + A::operator int() + int to double) would be compared to other implicit conversion sequences.

    这篇关于通过初始标准转换序列区分用户定义的转换序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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