Home > Software design >  Is it possible to deprecate implicit conversion while allowing explicit conversion?
Is it possible to deprecate implicit conversion while allowing explicit conversion?

Time:12-03

Suppose I have a simple Duration class:

class Duration
{
    int seconds;
public:
    Duration(int t_seconds) : seconds(t_seconds) { }
};

int main()
{
    Duration t(30);
    t = 60;
}

And I decide that I don't like being able to implicitly convert from int to Duration. I can make the constructor explicit:

class Duration
{
    int seconds;
public:
    explicit Duration(int t_seconds) : seconds(t_seconds) { }
};

int main()
{
    Duration t(30); // This is fine, conversion is explicit
    t = 60; // Doesn't compile: implicit conversion no longer present for operator=
}

But what if I don't want to immediately break all calling code that's implicitly converting to Duration? What I would like to have is something like:

class Duration
{
    int seconds;
public:
    [[deprecated]]
    Duration(int t_seconds) : seconds(t_seconds) { }

    explicit Duration(int t_seconds) : seconds(t_seconds) { }
};

int main()
{
    Duration t(30); // Compiles, no warnings, uses explicit constructor
    t = 60; // Compiles but emits a deprecation warning because it uses implicit conversion
}

This would allow existing code to compile while identifying any places that currently rely on implicit conversion, so they can either be rewritten to use explicit conversion if it's intended or rewritten to have correct behavior if not.

However this is impossible because I can't overload Duration::Duration(int) with Duration::Duration(int).

Is there a way to achieve something like this effect short of "Make the conversion explicit, accept that calling code won't compile until you've written the appropriate changes"?

CodePudding user response:

You can turn Duration(int t_seconds) into a template function that can accept an int and set it to deprecated.

#include<concepts>

class Duration {
  int seconds;
public:
  template<std::same_as<int> T>
  [[deprecated("uses implicit conversion")]]
  Duration(T t_seconds) : Duration(t_seconds) { }
  
  explicit Duration(int t_seconds) : seconds(t_seconds) { }
};

If you allow t = 0.6, just change the same_as to convertible_to.

Demo.

  • Related