我需要将在下一个C ++版本(C ++ 17)中添加的功能。我正在使用MS Visual Studio,它实现了C ++ 11。我希望在几年后我会升级我的编译工具,因此可以通过标准库获得此功能。
与此同时,我需要手动实现它。我如何定义它以便将来很容易迁移?
我们以std::clamp
为例。
my_clamp
。当我能够使用C ++ 17时,我可以开始使用std::clamp
,并可选择通过my_clamp
全局替换std::clamp
。这看起来很难看,但可能不会产生任何意外。my::std
中实现它,并执行using namespace my
。这样,我今天可以开始使用名称std::clamp
,而不是稍后更改它。但是,这是危险/禁止的吗?clamp
填充到std
命名空间中。这是UB,但可能会奏效。有没有缺点的方法?
是否有接受/习惯的方式这样做?
我在这些情况下通常做的是: 1.尝试使用最新的C ++编译器和库,它已经包含了我需要的功能/设施。 2.失败了(即我被迫使用较旧的C ++标准版本,让我们说C ++ 11,因为旧的工具链),找到一个我需要的库 3.更好的是,如果我需要的已经包含在更新的C ++标准或“参考实现”库中,我尝试使用参考实现或关闭实现,这将减少代码中的未来变化。 4.熟悉the boost library,因为它很可能已经包含了你需要的东西,它很可能是未来C ++标准的参考实现。 5.出于上述原因,无论出于何种原因,都要编写自己的实现,但要尽量使其界面与标准提案类似。
对于任何不是来自std :: namespace的东西,使用namespace aliasing进一步减少未来的变化(当切换到更新的工具链和std ::时)。
注1:C ++ 17是当前的C ++标准,接下来应该是C ++ 20。 注2:MS VS2017(以及2015年在某种程度上)已经包含了一些或大部分来自C ++ 17的东西。
编辑包含如何使用命名空间别名的示例 这个例子与C ++文件系统的东西有关,它还没有(更新)使用C ++ 17,但它仍然受限于。 它主要依靠预处理器#defines(即HAVE_CXX_EXPERIMENTAL_FILESYSTEM)来启用/禁用所需部分。我通常使用CMake来检测编译器和库的功能,并以自动方式定义这些宏。
#if _MSC_VER >= 1900 // Microsoft Visual C++ 2015
#define HAVE_CXX_EXPERIMENTAL_FILESYSTEM
#endif
#if defined(HAVE_CXX_EXPERIMENTAL_FILESYSTEM)
// Have Filesystem TS
#include <experimental/filesystem>
namespace filesystem = std::experimental::filesystem;
using std::error_code;
#elif !defined(NO_BOOST)
// Fall-back to Boost.Filesystem library
#include <boost/version.hpp>
#if (BOOST_VERSION >= 103400)
#include <boost/filesystem.hpp>
#else
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/filesystem/exception.hpp>
#endif // (BOOST_VERSION >= 103400)
namespace filesystem = boost::filesystem;
using boost::system::error_code;
// Hack to fix differences with C++17 Filesystem TS
#define copy_options copy_option
#define overwrite_existing overwrite_if_exists
#else
#warning Not implemented
// or #include custom stuff
#endif
以上基本上做的是落实: 1.如果可用,请使用和别名命名空间 2.使用boost.filesystem(如果没有用NO_BOOST明确排除) 3. [可选]如果需要,回退到自定义实现或其他库。
免责声明:此解决方案可能并不完美,但它可以合理地满足我的需求。