Search code examples
c++type-conversionoperator-overloadingidioms

idiomatic way for `class<T>` to `class<const T>` conversion operator


Suppose there is a template class template <class T> myclass;.

Is there an idiomatic way to allow conversion of objects of non-const T to objects of const T?

Basically, I want the following conversion to happen implicitly:

void f(myclass<const int> x);

myclass<int> a;
f(a); // should compile

IMPORTANT EDIT:

It appears that the answer is very trivial (and the question is quite silly) but there is something very conceptual involved (at least for me).

I was under the impression that I need to conditionally enable a conversion operator because a conversion operator from myclass<const T> to myclass<const T> doesn't make any sense, i.e. I need to declare the conversion operator if and only if T was const qualified. I was expecting the compiler to complain about a redundant conversion operator.

Now given that the compiler is happy with the identity conversion operator which converts type X to X, what's the difference between the assignment operator or the copy constructor and the identity conversion operator?

MSVC throws a warning for an identity conversion operator. This isn't great.


Solution

  • You can do this using a conversion operator that returns a myclass with the type const qualified. That looks like

    template<typename T>
    struct myclass
    {
        T foo;
        operator myclass<const T>() { return myclass<const T>{foo}; }
    };
    

    and then in

    int main() 
    { 
        myclass<int> a{42};
        f(a); // should compile
    }
    

    the compiler will implicitly call it for you.


    If you already have a myclass<const int> and you pass it to f you don't have to worry about any ambiguity since the copy constructor is an exact match so that is what is called. However, if you do want to disable the conversion operator when T is already const then you can use

    template<typename U = T, std::enable_if_t<!std::is_const_v<U>, bool> = true> 
    operator myclass<const U>() { return myclass<const U>{foo}; }