28

Is it possible to mark an enum value as deprecated?

e.g.

enum MyEnum {
    firstvalue = 0
    secondvalue,
    thirdvalue, // deprecated
    fourthvalue
};

A second prize solution would be to ifdef a MSVC and a GCC solution.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
moala
  • 5,094
  • 9
  • 45
  • 66
  • 3
    What do you want to happen? Just rename it, and the compiler will issue an error... – Lindydancer Mar 30 '11 at 15:00
  • 4
    @Lindydancer: But that goes a bit beyond deprecation, does it not? I think the point is to allow existing code to compile but to issue a warning about the deprecated resource. – Fred Larson Mar 30 '11 at 15:07
  • 8
    @Lindydancer: had it been sufficient, deprecation would not have been needed on classes, functions, types either... – moala Mar 30 '11 at 15:08
  • Would it be possible to 1) rename the deprecated enum value, 2) #define a macro that maps the deprecated token to the renamed token, but also includes some warning text, like a pragma or something? – JCooper Mar 30 '11 at 15:31
  • @JCooper: sound like an interesting solution, using `_Pragma` you can indeed include a pragma in the expansion of a macro. Why don't you post an answer ? – Matthieu M. Mar 30 '11 at 15:45
  • 1
    Hopefully the correct solution/hack would also work with scoped enums in C++0x =] – David Mar 30 '11 at 16:38
  • Hi @moala, none of the answers are accepted yet, but can you accept https://stackoverflow.com/a/20266156/194921 as the modern way to do this? (as of C++14) – Paul Du Bois Aug 07 '20 at 21:27

9 Answers9

14

You can use the [[deprecated]] attribute from C++14 on.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html

So, you would write this:

enum MyEnum {
    firstvalue = 0
    secondvalue,
    thirdvalue [[deprecated]],
    fourthvalue
};

When you deprecate an enum value with value explicitly assigned, then it would look like this:

enum MyEnum {
    firstvalue = 0
    secondvalue,
    thirdvalue [[deprecated]] = 2,
    fourthvalue
};
László Papp
  • 51,870
  • 39
  • 111
  • 135
14

you could do this:

enum MyEnum {
    firstvalue = 0,
    secondvalue,
    thirdvalue, // deprecated
    fourthvalue
};
#pragma deprecated(thirdvalue)

then when ever the variable is used, the compiler will output the following:

warning C4995: 'thirdvalue': name was marked as #pragma deprecated

EDIT
This looks a bit hacky and i dont have a GCC compiler to confirm (could someone do that for me?) but it should work:

enum MyEnum {
    firstvalue = 0,
    secondvalue,
#ifdef _MSC_VER
    thirdvalue,
#endif
    fourthvalue = secondvalue + 2
};

#ifdef __GNUC__
__attribute__ ((deprecated)) const MyEnum thirdvalue = MyEnum(secondvalue + 1);
#elif defined _MSC_VER
#pragma deprecated(thirdvalue)
#endif

it's a combination of my answer and MSalters' answer

Tom
  • 908
  • 1
  • 6
  • 14
  • Do you know if it is possible to make it nicer? without "in-between" #ifdef _MSC_VER? I am trying to write a macro to handle it cross-platform, but that makes it a bit more unpleasant for the end user. It would be nice if the end user could use a self-contained macro. – László Papp Nov 28 '13 at 12:36
  • Another point to have it without ifdef, it could potentially break the binary compatibility based on the underlying enum representation on the given platform. – László Papp Dec 03 '13 at 17:00
  • Good solution, but unfortunately this will not work for C++11 code that uses the enum scope like this: `MyEnum test = MyEnum::thirdvalue;` – Konstantin May 24 '18 at 07:40
7

Beginning with GCC 6 you can simply deprecate enums:

enum {
  newval,
  oldval __attribute__ ((deprecated ("too old")))
};

Source: https://gcc.gnu.org/gcc-6/changes.html

usr1234567
  • 21,601
  • 16
  • 108
  • 128
3

Well, since we're at macro hacks already, here is mine :-)

enum MyEnum
{
 foo,
 bar,
 baz
};

typedef __attribute__ ((deprecated))MyEnum MyEnum_deprecated;
#define bar ((MyEnum_deprecated) bar)

int main ()
{
    int a = foo; // yuck, why did C++ ever allow that...
    int b = bar;

    MyEnum c = foo;
    MyEnum d = bar;

    return 0;
}

This works with gcc, and it does not require you to break type-safety. Unluckily it still abuses your code with macros, so meh. But as far as I could figure, it's as good as it gets.

The proposal made by Tom is much cleaner (works for MSVC, I assume), but unluckily the only message gcc will give you is "ignoring pragma".

Damon
  • 67,688
  • 20
  • 135
  • 185
  • Will this work properly with an enum inside a class or namespace? – László Papp Nov 28 '13 at 12:46
  • Since it is a macro hack, it will "work" with enums inside namespaces even better than you would wish. That's the downside of macros, they merely replace text and do not respect namespaces. Unluckly you can't assign an attribute to a single enumerator, only to the complete thing. So you have to do such a kind of hack to make it work. – Damon Nov 28 '13 at 14:03
  • Actually, it will not work with namespaces without further user inconvenience, so this solution is -1 from my side. Also, it has the limitation that no common macro can wrap it since the macro inside the macro will break... It will even break further with C++11 class enums. – László Papp Nov 29 '13 at 06:06
  • The question was neither about namespaces nor C++11, though. Besides, I see no reason why it shouldn't work with C++11 enums if you use them properly qualified, as you have to do anyway. Also why do you think nested macros would not work? They work elsewhere, why not in this case? – Damon Nov 29 '13 at 11:16
  • Damon: how would you make it work with nested macros? As far as I see the define would be evaluated where it is defined rather than the actual macro call surrounding the redefinition, no? Please highlight my name next time, otherwise I can miss the reply like I did here. – László Papp Dec 03 '13 at 16:31
3

You can declare enum constants outside an enum declaration:

enum MyEnum {
    firstvalue = 0
    secondvalue,
    thirdvalue
};
__attribute__ ((deprecated)) const MyEnum fourthvalue = MyEnum(thirdvalue + 1);
MSalters
  • 173,980
  • 10
  • 155
  • 350
1

Using compiler dependent pragmas: Here is the documentation for Gcc and Visual Studio.

Sadique
  • 22,572
  • 7
  • 65
  • 91
  • 3
    This doesn't really answer the question, e.g. gcc allows functions, types and variables to be flagged as "deprecated", but there is no mention of applying this to specific enum values. – Paul R Mar 30 '11 at 15:09
  • 2
    Sadly, gcc does not let you specify an attribute to an enum value, only on the entire enum type. You could of course create two enums (one with the deprecated values) as a workaround hack, but then of course they'd have different types. – Damon Mar 30 '11 at 15:13
  • @Damon: maybe with a reference, that would have been a great answer. – moala Mar 30 '11 at 15:15
  • The reference would be the compiler's error message (I've tried the exact same thing in the past!) and the lack of mention in the docs whereas there is explicit mention for types, variables, and functions. Unluckily, my "solution" is not as great as it sounds, as it would necessarily involve casting enums to int. There is a good reason why enums are typed (even stronger in C++0x), tampering with and cheating on the type system is not what one would normally want to do. – Damon Mar 30 '11 at 15:20
  • There is actually a solution which is reasonably typesafe, but it is not pretty either (uses typedefs and defines). – Damon Mar 30 '11 at 15:35
1

You might be able to use some macro hackery.

enum MyEnum {
    firstvalue = 0
    secondvalue,
    real_thirdvalue, // deprecated
    fourthvalue
};

template <MyEnum v>
struct real_value
{
    static MyEnum value()
    { 
        1 != 2U;  // Cause a warning in for example g++. Leave a comment behind for the user to translate this warning into "thirdvalue is deprecated"
        return v;
    }
};

#define thirdvalue (real_value<real_thirdvalue>::value());

This won't work in a context when a constant is needed.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

I have a solution (inspired from Mark B's) that makes use of boost/serialization/static_warning.hpp. However, mine allows thirdvalue to be used as a symbolic constant. It also produces warnings for each place where someone attempts to use thirdvalue.

#include <boost/serialization/static_warning.hpp>

enum MyEnum {
    firstvalue = 0,
    secondvalue,
    deprecated_thirdvalue, // deprecated
    fourthvalue
};

template <int line>
struct Deprecated
{
    BOOST_SERIALIZATION_BSW(false, line);
    enum {MyEnum_thirdvalue = deprecated_thirdvalue};
};

#define thirdvalue (static_cast<MyEnum>(Deprecated<__LINE__>::MyEnum_thirdvalue))

enum {symbolic_constant = thirdvalue};

int main()
{
    MyEnum e = thirdvalue;
}

On GCC I get warnings that ultimately point to the culprit lines containing thirdvalue.

Note that the use of the Deprecated template makes it so that an "instantiated here" compiler output line shows where the deprecated enum is used.

If you can figure out a way to portably generate a warning inside the Deprecated template, then you can do away with the dependency on Boost.

Emile Cormier
  • 28,391
  • 15
  • 94
  • 122
0

C++14's support for a standard syntax attributes (including [[deprecated]]) improved on that of C++11's by allowing enumerators also to be annotated (see N3760). This means the OP's example can now look like this:

enum MyEnum {
  firstvalue = 0,
  secondvalue,
  thirdvalue [[deprecated]],
  fourthvalue
};
user2023370
  • 10,488
  • 6
  • 50
  • 83