我想创建使用标准C ++中的“可选”的标头。但是,我的标题将从Visual Studio 2015以及Visual Studio 2017项目中引用。
我希望有一些东西,例如,对于Visual Studio 2017(使用C ++ 17 lang功能集),使用std :: optional,使用Visual Studio 2015,使用boost :: optional。
我在考虑这样的事情:
#include <yvals.h>
#if _HAS_CXX17
#include <optional>
template <typename T> using Optional = std::optional<T>;
#else
#include "boost/optional/optional.hpp"
template <typename T> using Optional = boost::optional<T>;
#endif
可以这样使用'_HAS_CXX17'宏吗?有没有更好的方法呢?
简短的回答是:否在Visual C ++运行时的实现中依赖内部预处理器定义是不安全的,并且技术上所有以单个_
开头的编译器符号都保留供实现使用。
例如,_NOEXCEPT
已在Visual Studio 2015和2017内部使用,但从VS 2017(15.8更新)开始,此宏不再存在;标题只是直接使用noexcept
。
使用__has_include
的建议很好,但在VS 2017(15.3更新)之前不支持。
另一个挑战是__cplusplus
并不表示你正在使用/std:c++17
,除非你使用VS 2017(15.7更新)与新的/Zc:__cplusplus
开关默认关闭。
在一系列VS版本中执行此操作的最安全方法可能是:
#if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201703L) && (_MSC_VER >= 1913))
#if __has_include(<optional>)
#include <optional>
template <typename T> using Optional = std::optional<T>;
#else
#include "boost/optional/optional.hpp"
template <typename T> using Optional = boost::optional<T>;
#endif
#else
#include "boost/optional/optional.hpp"
template <typename T> using Optional = boost::optional<T>;
#endif