Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

type-casting between instances of template class

I am currently experimenting with the c++ style type-casts. For this, I created a template class pClass, which takes some element of type T and prints it.

Now I would (for example) like to convert an instance of type pClass<char> to pClass<int>. However, non my type casting attempts seems to work as expected.

I already found out that dynamic_cast is used for conversion at runtime and when dealing with virtual functions / polymorphic classes, which is not the case here. static_cast is used for conversion at compile time. So, in my case static_cast should be the right choice, I think?

Some topics here on stackoverflow had similar questions, but only when handling multiple classes with some inheritance going on between them. Unfortunately, I could not really relate them to my problem (e.g. C++ Casting between template invocations).

#include <iostream>

template <typename T>
class pClass {
    public:
    T value;
    pClass(T value) {
        this->value = value;
        std::cout << value << std::endl;
    }
    virtual ~pClass() {}
};

int main() {
    pClass<int> pInt(5);
    pClass<char> pChar('a');
    pClass<float> pFloat(4.2f);

    // pClass<int> pInt2 = static_cast<pClass<int>&>(pChar); //  gives invalid type conversation
    // pClass<int>& pInt3 = dynamic_cast<pClass<int>&>(pChar); // warning: dynamic_cast of ‘pClass<char> pChar’ to ‘class pClass<int>&’ can never succeed
    // pClass<int> pInt4 = reinterpret_cast<pClass<int>&>(pChar); // works, but does not print anything
    // std::cout << pInt2.value << std::endl; // prints 3277 or even 327777 exept of 97, which is the expected ASCII representation
}

For each casting attempt I wrote the error message / the resulting output behind the command. I appreciate any hint that can help me finding the correct type of casting here.

Thank you very much!

like image 857
kanra Avatar asked Mar 03 '23 20:03

kanra


1 Answers

Although the types come from the same template, they are completely unrelated. You cannot just cast between them, how can the compiler know what you mean by the cast? Due to template specialization, pClass<char> might not even contain a char that can be cast to int.

The solution is to write the meaning of casting using a cast conversion operator:

template <typename T>
class pClass {
    public:
    T value;
    pClass(T value) {
        this->value = value;
        std::cout << value << std::endl;
    }
    virtual ~pClass() {}

    template<typename U>
    operator pClass<U>(){
        return pClass<U>(static_cast<U>(this->value));
    }
};

The above method allows casting between any two pClass<T> and pClass<U> objects by casting the stored value. This will make the following code compile:

pClass<int> pInt{1};
pClass<float> pfloat{pInt};

Where the second line calls a copy constructor pClass<float>::pClass<float>(const pClass<float>&); which uses the implicit cast to convert pInt to pClass<float> type.

I would recommend making the conversion operator explicit:

template<typename U> explicit operator pClass<U>()

This will forbid the implicit conversion above but still allows explicit cast:

pClass<float> pfloat{static_cast<pClass<float>>(pInt)};
like image 174
Quimby Avatar answered Mar 22 '23 22:03

Quimby