【问题标题】:c++ mark enum value as deprecated?c++ 将枚举值标记为已弃用?
【发布时间】:2011-03-30 14:57:35
【问题描述】:

是否可以将枚举值标记为已弃用?

例如

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

二等奖的解决方案是 ifdef 一个 MSVC 和一个 GCC 解决方案。

【问题讨论】:

  • 你想要发生什么?只要重命名,编译器就会报错...
  • @Lindydancer:但这有点过时了,不是吗?我认为重点是允许现有代码编译,但发出有关已弃用资源的警告。
  • @Lindydancer:如果足够的话,类、函数、类型也不需要弃用......
  • 是否有可能 1) 重命名已弃用的枚举值,2) #define 一个将已弃用的令牌映射到重命名的令牌的宏,但还包括一些警告文本,如编译指示或其他内容?
  • 希望正确的解决方案/hack 也适用于 C++0x 中的作用域枚举 =]

标签: c++ enums deprecated


【解决方案1】:

你可以这样做:

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

然后,当使用该变量时,编译器将输出以下内容:

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

编辑
这看起来有点 hacky,我没有 GCC 编译器来确认(有人可以帮我做吗?)但它应该可以工作:

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

这是我的回答和 MSalters 的回答的结合

【讨论】:

  • 你知道是否可以让它变得更好吗?没有“中间”#ifdef _MSC_VER?我正在尝试编写一个宏来跨平台处理它,但这会让最终用户更加不愉快。如果最终用户可以使用自包含宏,那就太好了。
  • 在没有 ifdef 的情况下还有一点,它可能会破坏基于给定平台上底层枚举表示的二进制兼容性。
  • 很好的解决方案,但不幸的是,这不适用于像这样使用枚举范围的 C++11 代码:MyEnum test = MyEnum::thirdvalue;
【解决方案2】:

您可以从 C++14 开始使用 [[deprecated]] 属性。

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

【讨论】:

  • 示例如下所示:enum E { A [[deprecated]] = 3, B };
【解决方案3】:

从 GCC 6 开始,您可以简单地弃用枚举:

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

来源:https://gcc.gnu.org/gcc-6/changes.html

【讨论】:

    【解决方案4】:

    您可以在枚举声明之外声明枚举常量:

    enum MyEnum {
        firstvalue = 0
        secondvalue,
        thirdvalue
    };
    __attribute__ ((deprecated)) const MyEnum fourthvalue = MyEnum(thirdvalue + 1);
    

    【讨论】:

    • 这不适用于 msvc,也不适用于 C++11 类枚举。
    • 如果编译器为 MyEnum 选择的基础类型不足以容纳您分配的值 (thirdvalue + 1),它也会中断。
    【解决方案5】:

    好吧,既然我们已经在使用宏 hack,这是我的 :-)

    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;
    }
    

    这适用于 gcc,并且不需要您破坏类型安全。不幸的是,它仍然使用宏滥用您的代码,所以嗯。但据我所知,它已经做得很好了。

    Tom 提出的建议更简洁(我认为适用于 MSVC),但不幸的是 gcc 给您的唯一信息是“忽略 pragma”。

    【讨论】:

    • 在类或命名空间中使用枚举是否可以正常工作?
    • 因为它是一个宏 hack,它会比你希望的更好地与命名空间内的枚举一起“工作”。这是宏的缺点,它们只是替换文本并且不尊重命名空间。不幸的是,您不能将属性分配给单个枚举器,而只能分配给完整的事物。所以你必须做这样一种 hack 才能让它工作。
    • 实际上,如果没有进一步的用户不便,它不适用于命名空间,所以这个解决方案在我这边是-1。此外,它有一个限制,即没有通用宏可以包装它,因为宏内部的宏会破坏......它甚至会进一步破坏 C++11 类枚举。
    • 不过,问题既不是关于命名空间也不是 C++11。此外,如果您使用适当的限定符,我认为它不应该与 C++11 枚举一起使用,因为无论如何您都必须这样做。另外,为什么您认为嵌套宏不起作用?他们在其他地方工作,为什么不在这种情况下?
    • Damon:你如何让它与嵌套宏一起工作?据我所见,定义将在定义的位置进行评估,而不是围绕重新定义的实际宏调用,不是吗?请下次突出显示我的名字,否则我会像这里一样错过回复。
    【解决方案6】:

    使用编译器相关的编译指示:这是GccVisual Studio 的文档。

    【讨论】:

    • 这并不能真正回答问题,例如gcc 允许将函数、类型和变量标记为“已弃用”,但没有提及将其应用于特定的枚举值。
    • 遗憾的是,gcc 不允许您为枚举值指定属性,只能在整个枚举类型上。您当然可以创建两个枚举(一个具有不推荐使用的值)作为解决方法,但是它们当然会有不同的类型。
    • @Damon:也许有参考,那将是一个很好的答案。
    • 引用将是编译器的错误消息(我过去尝试过完全相同的事情!)并且文档中没有提及,而明确提及类型、变量和函数.不幸的是,我的“解决方案”并不像听起来那么好,因为它必然涉及将枚举转换为 int。枚举类型有一个很好的理由(在 C++0x 中甚至更强大),篡改和欺骗类型系统并不是人们通常想要做的。
    • 实际上有一个相当类型安全的解决方案,但也不是很漂亮(使用 typedef 和定义)。
    【解决方案7】:

    你也许可以使用一些宏骇客。

    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());
    

    这在需要常量的上下文中不起作用。

    【讨论】:

    • 我不知道这是否有效,但 +1 表示纯粹的血腥骇客。 ;-)
    • 你为什么要这么疯狂?
    【解决方案8】:

    我有一个使用 boost/serialization/static_warning.hpp 的解决方案(灵感来自 Mark B)。但是,我的允许 thirdvalue 用作符号常量。它还会为有人尝试使用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;
    }
    

    在 GCC 上,我收到的警告最终指向包含 thirdvalue 的罪魁祸首。

    请注意,Deprecated 模板的使用使得“instantiated here”编译器输出行显示不推荐使用的枚举的使用位置。

    如果您能找到一种在 Deprecated 模板中可移植地生成警告的方法,那么您就可以摆脱对 Boost 的依赖。

    【讨论】:

      【解决方案9】:

      C++14 对标准语法属性(包括 [[deprecated]])的支持在 C++11 的基础上进行了改进,它允许对枚举数进行注释(参见 N3760)。这意味着 OP 的示例现在看起来像这样:

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

      【讨论】:

        猜你喜欢
        • 2012-03-14
        • 2012-01-25
        • 1970-01-01
        • 2023-04-10
        • 2010-09-22
        • 2012-04-27
        • 2014-08-20
        • 2012-03-15
        • 1970-01-01
        相关资源
        最近更新 更多