C ++显式拷贝构造函数?

时间:2014-12-26 13:45:58

标签: c++ templates casting copy-constructor explicit

关于这个明确的复制构造函数问题,我已经碰壁了。我一直在写一个类来解决问题:

#include <iostream>

template<class T>
class Mat
{
private:
    T data;
public:
    void set(T value)
    {
        data = value;
    }

    Mat()
        : data(T(0))
    {
    }

    explicit Mat(const Mat& another)
    {
        *this = another;
    }

    Mat& operator=(const Mat& another)
    {
        data = another.data;
        return *this;
    }

    template<class U>
    explicit operator Mat<U>()
    {
        Mat<U> result;
        result.set(static_cast<U>(data));
        return result;
    }

    void print()
    {
        std::cout << data << std::endl;
    }
};


int main()
{
    Mat< double > d1;
    d1.set(3.14159);
    Mat< int > i1(static_cast<Mat<int>>(d1));
    d1.print();
    i1.print();

    std::cin.sync();
    std::cin.ignore();
    return 0;
}

我希望我的复制构造函数只接受另一个对象的显式转换实例,所以我声明它是显式的,但现在我得到了错误错误&#34; C2558:class&#39; Mat&#39; :没有复制构造函数可用,或者复制构造函数被声明为&#39;&#39;&#34;&#34;&#34;&#34;&#34;&#34;&#34;&#34;&#34;&#34;&

static_cast<Mat<int>>(d1)

我已经宣布复制构造函数是显式的,因为我希望这是非法的:

Mat<float> a;
Mat<int>   b(a);

虽然,我希望以下内容保持合法:

Mat<float> a;
Mat<int>   b(static_cast<Mat<int>>(a));

编辑:我一直在修改这些概念,试图准确定义我想要的东西,我似乎得到了一些有趣的结果:

#include <iostream>

class MatB
{
private:
    float data;
public:
    MatB()
        :data(0.0f)
    {

    }

    void set(float value)
    {
        data = value;
    }

    float getData() const
    {
        return data;
    }

    void print()
    {
        std::cout << data << std::endl;
    }
};

class MatA
{
private:
    double data;
public:


    MatA()
        :data(0.0)
    {

    }

    void set(double value)
    {
        data = value;
    }

    double getData() const
    {
        return data;
    }

    explicit operator MatB()
    {
        MatB temp;
        temp.set(static_cast<float>(getData()));
        return temp;
    }

    void print()
    {
        std::cout << data << std::endl;
    }
};



class MatC
{
private: 
    int data;
public:

    MatC()
        :data(0)
    {

    }

    explicit MatC(const MatB& in)
        :data(static_cast<int>(in.getData()))
    {

    }

    void print()
    {
        std::cout << data << std::endl;
    }
};

int main()
{
    MatA someA;
    someA.set(3.14159);
    MatC constructCFromA(someA);
    someA.print();
    constructCFromA.print();

    std::cin.sync();
    std::cin.ignore();
    return 0;
}

在这个例子中,constructCFromA(someA)不应该编译(imo) - 即使链接器将它标记为错误(VS2013),它仍然编译得很好......我不确定我是否理解& #39;明确&#39;是不正确的,IDE是否将其标记为错误,或者编译器编译它,即使它不应该。我以为我需要做这样的事情:

constructCFromA(static_cast<MatB>(someA));

IDE似乎同意我的意见,但编译器并不是这样。我必须说我很困惑。

EDIT2: 没关系,在Ideone中它没有编译,所以我想MS应该受到责备。 我认为第二个代码很好地说明了我想要的行为。基本上在初始化和赋值时进行非显式转换是非法的。然而,似乎使复制构造函数显式具有各种副作用&#34;。

2 个答案:

答案 0 :(得分:4)

您进行显式转换的行不是问题。导致编译问题的问题在于您按值返回Mat<U>的行:

template<class U>
explicit operator Mat<U>()
{
    Mat<U> result;
    result.set(static_cast<U>(data));
    return result;  // <<== This line requires a copy constructor to be defined
}

这就是为什么当你在复制文件之前删除explicit时,你的代码就可以了。

答案 1 :(得分:2)

这是另一个版本,它将通过您的单元测试而无需转换运算符到T:

    template<class T>
    class Mat
    {
    private:
        T data;
    public:
        void set(T value)
        {
            data = value;
        }

        // default constructor
        Mat()
        : data(T(0))
        {
        }

        // construct from data type
        explicit Mat(T dat)
        : data(dat)
        {}

        // construct from any compatible Mat
        template<class U>
        explicit Mat(const Mat<U>& another)
        : data(static_cast<T>(another.get_data()))
        {}

        // assign from any compatible Mat
        template<class U>
        Mat& operator=(const Mat<U>& another)
        {
            data = static_cast<T>(another.get_data());
            return *this;
        }

        // provide a means to access data from unrelated Mat
        const T& get_data() const { return data; }

        void print()
        {
            std::cout << data << std::endl;
        }
    };