JVApen
JVApen

Reputation: 11317

How to delete classes while keeping deprecation warnings

I am trying to look for a good way to remove deprecated classes from my library while keeping nice error messages. This idea is based upon something I already do with functions:

namespace
{
    [[deprecated("This function has been replaced by combust()")]]
    void explode() = delete; // Using variadic templates in reality to have all signatures covered

    void combust() {}
}

int main()
{
    explode();
    combust();
}

In clang, this gives me a nice error message:

<source>:11:2: error: call to deleted function 'explode': This function has been replaced by combust()
explode();
^~~~~~~

GCC only gives me only the message that this function has been deleted. Though, this still shows the intent for everyone trying to upgrade the library who was ignoring the deprecation warning.

So, since this is a c++ library, I mainly have classes and am looking for correct way to do something similar with these classes. My current approach looks like this:

namespace
{
    class [[deprecated("Class has been replaced by Bar")]] Foo
    {
        Foo () = delete; // And every other method I had in this class
    };
    class Bar
    {
    };
}

int main()
{
    Foo f;
    Bar b;
}

This basically gives me the following warnings/errors in clang (and similar in GCC):

<source>:13:5: warning: 'Foo' is deprecated: Class has been replaced by Bar [-Wdeprecated-declarations]
Foo f;
^
<source>:3:60: note: 'Foo' has been explicitly marked deprecated here
class [[deprecated("Class has been replaced by Bar")]] Foo
^
<source>:13:9: error: call to deleted constructor of '(anonymous namespace)::Foo'
Foo f;
^
<source>:5:8: note: 'Foo' has been explicitly marked deleted here
Foo () = delete;
^

Where I can live with this useless code for functions as this are one-liners, this becomes cumbersome for classes as they can have a lot of methods.

So, what I'm searching for, is a good way of doing the following: (non-compiling code)

class [[deprecated("Class has been replaced by Bar")]] Foo = delete;

The closed I got to a oneliner is:

struct [[deprecated("Class has been replaced by Bar")]] Foo { Foo() = delete; };
struct [[deprecated("Class has been replaced by Bar")]] Foo;

Note that doesn't cover the cases where Foo is passed by reference and some methods are called.

Does anyone have a better solution to delete classes while having clear deprecation warnings for some of the following releases?

Upvotes: 4

Views: 168

Answers (1)

ralismark
ralismark

Reputation: 806

It is possible to do this with static_assert, since it causes a compile-time error with a message. However, it will always assert if placed in a non-templated function. To counter this, we make it a template function, with the assert dependent on the parameter. This will not cause an error if the function is not used, since it will not be instantiated.

template <int I = 0>
void explode()
{
    static_assert(I && false, "This function has been replaced by combust()");
}

int main()
{
    // error: static_assert failed: "This function has been replaced by combust()"
    explode();
}

This can also be used for classes. However, a typedef needs to be used since template arguments are required.

namespace
{
    template <int I = 0>
    class FooDeprec
    {
        static_assert(I && false, "Class has been replaced by Bar");

        FooDeprec() = default; // no need to delete
    };

    using Foo = FooDeprec<>;
}

int main()
{
    // error: static_assert failed "Class has been replaced by Bar"
    Foo f;
}

The benefit of this is that not much change is needed - you can keep the declarations of member functions.

Upvotes: 2

Related Questions