繁体   English   中英

将原始数据类型解释为用户类

[英]Interpret primitive data type as user class

TLDR; 我想使用为我的班级定义的运算符,并使用原始数据类型将其转换为我的班级,而无需类型转换/初始化新变量。

mycomplex x = 5 , y ;
y = x + 3 ;

作为辅助项目,我正在开发复数类。 出于明显的原因,任何原始数字数据类型都可以解释为复数。 因此,在任何涉及原始类型和复数的运算中,我都希望允许原始类型转换为复数,并使用定义的涉及两个复数的运算继续运算。

每个基本类型都可以在每个运算符上重载,但顺序很重要,并且具有4个基本运算符和一些高级数学函数,它将很快变成大量代码。 因此,问题是,如何编写我的类,以便基本类型将“投射”到复杂对象并执行常规的复杂操作。

如果main的倒数第二行被注释掉,则此代码编译。 这里的目标是使该行评估为cout为8 + 2i的mycomplex。

#include <iostream>

template <class T>
class mycomplex{
    private:
        T real ; 
        T imag ; 
    public:
        mycomplex( const mycomplex<T> & x ) ;
        mycomplex( const T & realx , const T & imagx ) ; 
        mycomplex( const T & x ) ; 
        mycomplex( ) ;

        template <class U>
        friend std::ostream & operator << ( std::ostream & os , const mycomplex<U> & x ) ;

        template <class U>
        friend mycomplex<U> operator + ( const mycomplex<U> & lhs , const mycomplex<U> & rhs ) ;
} ;

int main( int argc , char * argv[] ){
    mycomplex<float> x = 5 , y( 3 , 2 ) ; 
    mycomplex<float> z = y + x ; 
    std::cout << x << '\n' << y << '\n' << z << std::endl ;
    z = 5 + y ; 
    return 0 ;
}

template <class T>
mycomplex<T>::mycomplex( const mycomplex<T> & x ){
    real = x.real ;
    imag = x.imag ; 
}
template <class T>
mycomplex<T>::mycomplex( const T & realx , const T & imagx ){
    real = realx ; 
    imag = imagx ; 
}
template <class T>
mycomplex<T>::mycomplex( const T & x ){
    real = x ; 
    imag = 0 ;
}
template <class T>
mycomplex<T>::mycomplex( ){
    real = 0 ; 
    imag = 0 ; 
}
template <class T>
std::ostream & operator << ( std::ostream & os , const mycomplex<T> & x ){
    os << x.real ; 
    if( x.imag >= 0 ) 
        os << "+" ;
    os << x.imag << "i" ;
    return os ;
}
template <class T>
mycomplex<T> operator + ( const mycomplex<T> & lhs , const mycomplex<T> & rhs ){
    mycomplex<T> ans ;
    ans.real = lhs.real + rhs.real ; 
    ans.imag = lhs.imag + rhs.imag ; 
    return ans ; 
}

我看了这个答案,并实现了该功能,如您在上面看到的那样,但这虽然让您在声明变量时很方便,却无法进行编译。 我还查看了此答案,并在模板类型中添加了类型转换,但这使我的班级转到模板,这与目标恰好相反。 它允许上面的代码进行编译,但是任何mycomplex + T都会给出没有虚构部分的mycomplex,这是不正确的。

您可以使用std :: enable_if,但是非常丑陋。

我很着急,很遗憾,我没有对此进行广泛测试或未启用促销功能( float + complex<int>给您complex<float> )。 可运行的代码在这里

#include <iostream>
#include <type_traits>

template <class T>
class mycomplex{
    private:
        T r ; 
        T i ; 
    public:
        using Underlying = T;
        mycomplex( const mycomplex<T> & x ) ;
        mycomplex( const T & realx , const T & imagx ) ; 
        mycomplex( const T & x ) ; 
        mycomplex( ) ;

        T real() const{
            return r;
        }
        T imag() const {
            return i;
        }

        template <class U>
        friend std::ostream & operator << ( std::ostream & os , const mycomplex<U> & x ) ;
} ;

template <class T>
mycomplex<T>::mycomplex( const mycomplex<T> & x ){
    r = x.r ;
    i = x.i ; 
}
template <class T>
mycomplex<T>::mycomplex( const T & realx , const T & imagx ){
    r = realx ; 
    i = imagx ; 
}
template <class T>
mycomplex<T>::mycomplex( const T & x ){
    r = x ; 
    i = 0 ;
}
template <class T>
mycomplex<T>::mycomplex( ){
    r = 0 ; 
    i = 0 ; 
}
template <class T>
std::ostream & operator << ( std::ostream & os , const mycomplex<T> & x ){
    os << x.r ; 
    if( x.i >= 0 ) 
        os << "+" ;
    os << x.i << "i" ;
    return os ;
}

template<typename T>
struct is_mycomplex : std::false_type{
};

template<typename T>
struct is_mycomplex<mycomplex<T>> : std::true_type{
};

static_assert(!is_mycomplex<int>::value);
static_assert(is_mycomplex<mycomplex<int>>::value);

template <typename T>
auto type_helper(){
    if constexpr (is_mycomplex<T>::value){
        return typename T::Underlying{};
    } else {
    return T{};
    }
}
template <class L, class R, typename = std::enable_if_t<
    is_mycomplex<L>::value + is_mycomplex<R>::value == 2
        ||
    (is_mycomplex<L>::value + is_mycomplex<R>::value == 1
     &&
     std::is_arithmetic_v<L> + std::is_arithmetic_v<R> ==1)
    >>
auto operator + ( const L& lhs , const R& rhs ){    
    using T = decltype(type_helper<L>());
    T real = 0; 
    T imag = 0;
    if constexpr(std::is_arithmetic_v<L>) {
        real+=lhs;
    } else {
        real+=lhs.real();
        imag+=lhs.imag();
    }
    if constexpr(std::is_arithmetic_v<R>) {
        real+=rhs;
    } else {
        real+=rhs.real();
        imag+=rhs.imag();
    }

    return mycomplex<T>(real, imag);
 ; 
}

int main(){
    mycomplex<float> x = 5 , y( 3 , 2 ) ; 
    mycomplex<float> z = y + x ; 
    std::cout << x << '\n' << y << '\n' << z << std::endl ;
    z = 5.5f + y ; 
    std::cout << "\n\n" << z << std::endl ;
}

让我们看一下这一行:

z = 5 + y ; 

ymycomplex<float> ,编译器首先要寻找一个operator+的重载,该重载采用整数(立即数5的类型是整数)和mycomplex<float> 这不存在,唯一的operator+ mycomplex两个mycomplex值。

由于y已经是mycomplex类型,因此编译器将尝试将5转换为mycomplex<float> 这将是不可能的,因为您只能将float值转换为mycomplex<float>

在这一点上很明显,没有可用的重载,也没有转换将使该行格式正确。 编译终止。

一种可能的解决方案是创建一个从任何东西mycomplex的转换运算符,并仅对数字类型启用它。

像这样:

template<class Z, std::enable_if_t<std::is_arithmetic_v<Z>>* = nullptr>
mycomplex(Z& z);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM