Home > Back-end >  Why template class assignment operator can use "templated copy constructor" to assign diff
Why template class assignment operator can use "templated copy constructor" to assign diff

Time:05-02

I have a template<class T> class Container {}.

While doing some code experiments, I realised that when I call the assigment operator (operator=()) with a different type (i.e. passing a different template parameter to my Container template class), it compiles.

It turns out that this is possible because I also have a "templated copy constructor" (I'm not sure what would be the proper name for this) which is called whenever I call the operator=() with a different argument type.

#include <iostream>

template<typename T>
class Container {
    
    public:
        Container() : data() { }

        Container(const Container &c) : data(c.data) {
            std::cout << "COPY CONSTRUCTOR" << std::endl;
        }

        // This is what I call a "templated copy constructor".
        // If I remove this, the operator=() does not compile with a different type
        template<class U>
        Container(const Container<U> &c) : data(c.getData()) {
            std::cout << "TEMPLATE COPY CONSTRUCTOR??" << std::endl;
        }

        Container &operator=(const Container &c) {
            std::cout << "assignment operator" << std::endl;

            if (this == &c)
                return *this;

            this->data = c.getData();
            return *this;
        }

        const T &getData() const {
            return this->data;
        }

    private:
        T data;
};

int main() {

    Container<int> c1;
    Container<float> c2;

    c2 = c1; // Assigning a Container<int> to a Container<float>

    return 0;
}

The code above compiles without any errors. If I remove the "templated copy constructor" the compiler gives me this error:

test.cpp:41:5: error: no viable overloaded '='
        c3 = c1;
        ~~ ^ ~~
test.cpp:18:14: note: candidate function not viable: no known conversion from 'Container<int>' to 'const Container<float>' for 1st argument
                Container &operator=(const Container &c) {

Can someone explain why this happens and what exactly does the "templated copy constructor" do? Thanks in advance! :)

CodePudding user response:

Your operator= only accepts a Container<T>, which in the case of c3 is a Container<int>.

Something needs to convert c1 from a Container<float> to a Container<int>. The copy constructor is doing that.

CodePudding user response:

Well. What exactly does "Class" mean? Or in another word, why we need operator-overloading for a class?

When we overload an operator, we define how to operate data belonging to the same class. Like there're two pieces of stone in front of us. How do we compare them? Let's declare and implement an overloaded operator '<' for it to solve this problem.

class Stone
{
public:
    bool operator<(const Stone& anotherStone)
    {
        return this->_weight < anotherStone._weight;
    }

    float _weight;
}

You see, the class of stone can then be compared. Similarity, we define the assignment of the same class of things by declaring and implementing '=' operator.

class Stone
{
public:
    bool operator<(const Stone& anotherStone)
    {
        return this->_weight < anotherStone._weight;
    }

    void operator=(const Strong& anotherStone)
    {
        this->_weight = anotherStone._weight;
    }

    float _weight;
}

In conclusion, we overload operators just for manipulating data within the same class, and that's the usage of operator-overloading.

For your code, c1 belongs to class Container and c2 belongs to class Container, they are totally different classes. It makes no sense to define a 'template copy constructor'.

But the compilation complains nothing just because the type 'int' and type 'float' could be converted one another implicitly. If the variable c2 is the type of Container, you will not be lucky like this.

  •  Tags:  
  • c
  • Related