Passer By
Passer By

Reputation: 21160

How to make a copy of a type?

As the title asks, how do I make a copy of a arbitrary type, but is different from the original type? As in, they are not implicitly convertible to each other but have the same interface.

I'll take cuda's pointers as an example to explain why this might be needed. Since host(CPU) and device(GPU) memory are separate, there is exactly 0 chance where you'd want to dereference a device pointer in host code. However, both are just plain old pointers, the compiler won't complain if you did actually do that. This is where type checking naturally fits in, these are all compile-time knowledge.

But then, to create a new pointer type, I'd have to manually type all the pointer arithmetic into a class to achieve this.

template<typename T>
class dptr
{
    //...
    dptr& operator++();
    //...
    auto& operator*();
    //...
    bool operator==(dptr) const;
    //...
    operator bool() const;
private:
    T* ptr;
};

And the boilerplate gets worse when the type to be copied is even more complicated and when noexcept is sprinkled in.

What I'm looking for is basically what Go have: strong retyping of arbitrary types

type Int int

Int is now an int, with arithmetic and all that, but is not implicitly convertible to int. (Actually, what I want is more like Go's type embedding, if the reader knows what that is.)

Upvotes: 0

Views: 149

Answers (1)

R Sahu
R Sahu

Reputation: 206747

I can think of couple of ways to do that. Both use strongly typed typedefs.

The first method assumes that you have the ability to define the main class, which can be a class template instead of a class.

template <typename Tag>
struct foo
{
   void bar() {}
};

using Type1 = foo<int>;
using Type2 = foo<float>;

int main()
{
   Type1 t1;
   Type2 t2;

   t1.bar(); // OK
   t2.bar(); // OK
   t2 = t1;  // Incorrect.
}

The second method is similar but it uses existing classes. It assumes that you don't have the ability to modify the main class.

// Existing class.
struct foo
{
   void bar() {}
};

// Bar can be used to create strongly typed typedefs.
template <typename Tag, typename Base>
struct Bar : public Base
{
};

using Type1 = Bar<int, foo>;
using Type2 = Bar<float, foo>;

int main()
{
   Type1 t1;
   Type2 t2;

   t1.bar(); // OK
   t2.bar(); // OK
   t2 = t1;  // Incorrect.
}

Upvotes: 3

Related Questions