如何弃用 C++ header?
How can I deprecate a C++ header?
我想弃用 C++ header,这样如果有人在他们的代码中包含它,编译器就会发出警告。
我知道我可以弃用单个符号,例如,使用 C++14 [[deprecated]]
,但是 headers 有类似的东西吗?也许是一些聪明的把戏?
请注意,即使用户未使用 header 中的任何内容,我也希望编译器发出警告。
如果您的 header 有一个命名空间,我猜您可以在上面使用 [[deprecated]]
?但这不适用于匿名名称空间。并且用户必须使用顶部空间的东西才能工作。
如果您可以将 header 放在命名空间中,那么您所要做的就是有一个 using
语句来触发警告。这也可能是隔离这些功能的好主意,并确保用户在使用它们时遇到更多困难,如果那是 objective。
namespace [[deprecated]] N {
struct S {
};
}
using N::S;
但是如果您负担不起命名空间,根据元素的数量,您可能不想对所有元素都使用 using
。
也许这可能是合法拥有 using namespace N;
的情况,但我不确定。
经过一些研究,您可以使用 #pragma message "Message"
来实现您似乎想要的。参见 this answer
这是一个可能的(虽然可能不太优雅)解决方案。
在 header 中插入这样的代码
// badheader.hpp
namespace {
[[deprecated("This header is deprecated")]]
constexpr static int badheader_hpp_is_deprecated = 0;
constexpr static int please_dont_use_badheader_hpp = badheader_hpp_is_deprecated;
}
这会创建一个已弃用的变量 badheader_hpp_is_deprecated
。 please_dont_use_badheader_hpp
的初始化触发弃用警告。请注意,我将两个变量都放在一个匿名命名空间中,以避免可能的名称冲突。
尽管如此,如评论中所述,如果在同一编译单元中,在匿名命名空间内声明了同名变量,名称冲突 可能 仍然会发生。出于这个原因,正如评论中所建议的那样,上面代码中的变量具有描述性名称,呈现名称冲突的可能性很高。
我建议用同名的命名空间围绕您的命名空间,并 using
它来自封闭的命名空间。
#pragma once
namespace your_namespace {
namespace [[deprecated]] your_namespace {
// old stuff
}
using namespace your_namespace;
}
这不应该用 your_namespace
中的任何内容污染您的全局命名空间,并且如果您包含 header 仍然会发出警告。旧内容仍可像以前一样通过 your_namespace::
访问。
由于这是一个 ABI 重大更改,如果您在弃用 header.
时还没有升级,我建议您也升级库的主要版本
一个非标准但相当便携的解决方案:
#pragma message("Header `foo.h` is deprecated!")
这是 GCC、Clang 和 MSVC 所接受的。 GCC 和 Clang 也接受没有 ( )
.
的形式
这不一定是“警告”,但应该足够好了。
这个是无耻抄袭的 range-v3 library:
#ifdef __GNUC__
#define RANGES_PRAGMA(X) _Pragma(#X)
#define RANGES_DEPRECATED_HEADER(MSG) RANGES_PRAGMA(GCC warning MSG)
#elif defined(_MSC_VER)
#define RANGES_STRINGIZE_(MSG) #MSG
#define RANGES_STRINGIZE(MSG) RANGES_STRINGIZE_(MSG)
#define RANGES_DEPRECATED_HEADER(MSG) \
__pragma(message(__FILE__ "(" RANGES_STRINGIZE(__LINE__) ") : Warning: " MSG))
#endif
RANGES_DEPRECATED_HEADER("Yikes! A deprecated header!")
我想弃用 C++ header,这样如果有人在他们的代码中包含它,编译器就会发出警告。
我知道我可以弃用单个符号,例如,使用 C++14 [[deprecated]]
,但是 headers 有类似的东西吗?也许是一些聪明的把戏?
请注意,即使用户未使用 header 中的任何内容,我也希望编译器发出警告。
如果您的 header 有一个命名空间,我猜您可以在上面使用 [[deprecated]]
?但这不适用于匿名名称空间。并且用户必须使用顶部空间的东西才能工作。
如果您可以将 header 放在命名空间中,那么您所要做的就是有一个 using
语句来触发警告。这也可能是隔离这些功能的好主意,并确保用户在使用它们时遇到更多困难,如果那是 objective。
namespace [[deprecated]] N {
struct S {
};
}
using N::S;
但是如果您负担不起命名空间,根据元素的数量,您可能不想对所有元素都使用 using
。
也许这可能是合法拥有 using namespace N;
的情况,但我不确定。
经过一些研究,您可以使用 #pragma message "Message"
来实现您似乎想要的。参见 this answer
这是一个可能的(虽然可能不太优雅)解决方案。
在 header 中插入这样的代码
// badheader.hpp
namespace {
[[deprecated("This header is deprecated")]]
constexpr static int badheader_hpp_is_deprecated = 0;
constexpr static int please_dont_use_badheader_hpp = badheader_hpp_is_deprecated;
}
这会创建一个已弃用的变量 badheader_hpp_is_deprecated
。 please_dont_use_badheader_hpp
的初始化触发弃用警告。请注意,我将两个变量都放在一个匿名命名空间中,以避免可能的名称冲突。
尽管如此,如评论中所述,如果在同一编译单元中,在匿名命名空间内声明了同名变量,名称冲突 可能 仍然会发生。出于这个原因,正如评论中所建议的那样,上面代码中的变量具有描述性名称,呈现名称冲突的可能性很高。
我建议用同名的命名空间围绕您的命名空间,并 using
它来自封闭的命名空间。
#pragma once
namespace your_namespace {
namespace [[deprecated]] your_namespace {
// old stuff
}
using namespace your_namespace;
}
这不应该用 your_namespace
中的任何内容污染您的全局命名空间,并且如果您包含 header 仍然会发出警告。旧内容仍可像以前一样通过 your_namespace::
访问。
由于这是一个 ABI 重大更改,如果您在弃用 header.
时还没有升级,我建议您也升级库的主要版本一个非标准但相当便携的解决方案:
#pragma message("Header `foo.h` is deprecated!")
这是 GCC、Clang 和 MSVC 所接受的。 GCC 和 Clang 也接受没有 ( )
.
这不一定是“警告”,但应该足够好了。
这个是无耻抄袭的 range-v3 library:
#ifdef __GNUC__
#define RANGES_PRAGMA(X) _Pragma(#X)
#define RANGES_DEPRECATED_HEADER(MSG) RANGES_PRAGMA(GCC warning MSG)
#elif defined(_MSC_VER)
#define RANGES_STRINGIZE_(MSG) #MSG
#define RANGES_STRINGIZE(MSG) RANGES_STRINGIZE_(MSG)
#define RANGES_DEPRECATED_HEADER(MSG) \
__pragma(message(__FILE__ "(" RANGES_STRINGIZE(__LINE__) ") : Warning: " MSG))
#endif
RANGES_DEPRECATED_HEADER("Yikes! A deprecated header!")