【问题标题】:Conversion Function with decltype(auto) in C++14C++14 中带有 decltype(auto) 的转换函数
【发布时间】:2017-03-24 15:02:08
【问题描述】:
class A {
    public:
        int num;
        A ( int param ) : num( param ) {}
        operator decltype( auto )( ){ return num; }
};

class B {
    public:
        int num;
        A objA;
        B ( int param ) : num( param ), objA( param ) {}
      //operator A( )       { return objA; }         // Works               // #1   
      //operator int( )     { return objA; }         // Works               // #2
      //operator char( )    { return objA; }         // Actually Not Needed // #3
      //operator double( )  { return objA; }         // Actually Not Needed // #4
        operator decltype( auto )( ){ return objA; } // Does NOT Work       // #5
};

int main(){

    A objA( 1 );
    int    x1 =   int( objA );
    char   y1 = (char) objA;
    double z1 =        objA;

    B objB( 2 );
    A objA2     = objB;
    int      x2 = objB;
    char     y2 = objB;
    double   z2 = objB;

    return 0;
}

这段代码既不能用 clang 也不能用 gcc 编译,所以我认为它是不正确的。但是,如果我注释第 5 行并取消注释第 1 行和第 2 行,则程序在两个编译器中都能正常工作(实际上并不需要第 3 行和第 4 行)。

据我所知,两种情况下都定义了必要的转换顺序。有谁知道为什么这个程序不正确?我错过了什么?

【问题讨论】:

    标签: c++ type-conversion c++14 auto decltype


    【解决方案1】:

    decltype(auto) 将获得您要返回的类型的确切类型(包括引用和指针)。对于class A,您的转换运算符将返回一个int,对于class B,您将得到它返回一个class A。我认为您的信念是 operator decltype(auto) (){/*...*/} 将尝试返回需要转换的类,而实际上您需要一个模板来这样做:

    class A {
        public:
            int num;
            A ( int param ) : num( param ) {}
    
            template<class T>
            operator T(){ return static_cast<T>(num); }
    };
    
    class B {
        public:
            int num;
            A objA;
            B ( int param ) : num( param ), objA( param ) {}
    
          template<class T>
          operator T ( ){ return static_cast<T>(objA); }
    };
    

    Live Demo

    【讨论】:

    • 感谢您的建议,非常有帮助。但是,我的主要兴趣是了解转换函数的过程,以及为什么它在这种情况下不起作用。当class B的转换函数应用并返回class A时,你知道为什么class A不能转换为int吗?定义了所需的转换顺序 (operator decltype( auto )( ){ return num; })。或者可能class B的转换功能一开始就没有应用?为什么?再次感谢您的帮助。
    • @JL 这是因为用户定义的转换不能链接。这就是songyuanyao's answer says
    【解决方案2】:

    请注意,implicit conversion sequence 只能包含一个用户定义的转换。那么代码将不适用于int x2 = objB;B 转换为AA 转换为int 都是自定义转换。

    如果您在B 中提供operator int(),它可以正常工作,因为B 可以直接转换为int。 (也适用于chardoubleint 可以通过标准转换转换为。)

    【讨论】:

    • 这听起来很有趣,我不知道那个规则。但是,在第二种情况下,您说 B 可以直接转换为 int,据我所知,还有 2 个用户定义的转换(B 不能直接转换为 int,因为该转换函数返回 A):当我提供operator int( ) { return objA; }(这是第一个用户定义的转换)它返回一个 A 类的对象,该对象应使用另一个用户定义的转换 operator decltype( auto )( ){ return num; } 转换为 int。这不是正确的吗?感谢您的帮助。
    • @JL 是的,对于return objA;objAA 中定义的转换运算符转换为int。但请注意,这是另一个转换序列;原始转换序列(即从Bint)已由B::operator int() 完成,表明它可以进行转换;它如何实现是另一回事。
    • 好的,我明白你的意思,但我不能对其他情况说同样的话吗?我想答案是否定的,这就是为什么它是错误的。所以使用operator decltype( auto )( ){ return objA; } 意味着两个用户定义的转换顺序相同,但在另一种情况下(operator int( ) { return objA; })有两个不同的转换顺序,对吗?我不完全理解为什么在一种情况下是相同的转换序列,而在另一种情况下它被认为是两个不同的转换序列,但这听起来像是正确的答案。再次感谢您的帮助:)
    • @JL 对于int x2 = objB;B 必须转换为int,这是一种转换;对于只允许一次用户定义的转换,这意味着我们不能在 之后调用另一个用户定义的转换操作。但是对于执行的唯一一个用户定义的转换,它是如何实现的(例如,它可能在其函数体中执行其他转换)不计算在内。
    • @JL int x2 = (A) objB; 被明确拆分为两个转换; BA,然后 Aint。两者都可以只通过一个用户定义的转换来完成,所以效果很好。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-18
    相关资源
    最近更新 更多