从这个Stack Overflow答案中,我了解到C ++ 17将具有__has_include,它可以


[make]从实验迁移到std几乎是无缝的


这仍然存在如何做的问题。像namespace std { using namespace std::experimental; }这样的操作是不确定的行为,所以我想出了以下方法:

optional.h在coliru上的演示

#pragma once

#if __has_include(<optional>)
#   include <optional>
#   define HAS_STD_OPTIONAL
#elif __has_include(<experimental/optional>)
#   include <experimental/optional>
#   define HAS_STD_EXPERIMENTAL_OPTIONAL
#else
#   error Must have an optional type, either from <optional> or if not supported from <experimental/optional>.
#endif

#if defined HAS_STD_OPTIONAL

namespace opt {
    template<class T>
    using optional = std::optional<T>;
    using bad_optional_access = std::bad_optional_access;
    using nullopt_t = std::nullopt_t;
    using in_place_t = std::in_place_t;

    constexpr auto nullopt = std::nullopt;
    constexpr auto in_place = std::in_place;

    template<class T>
    constexpr auto make_optional(T && value)
    {
        return std::make_optional(std::forward<T>(value));
    }
}

#elif defined HAS_STD_EXPERIMENTAL_OPTIONAL

namespace opt {
    template<class T>
    using optional = std::experimental::optional<T>;
    using bad_optional_access = std::experimental::bad_optional_access;
    using nullopt_t = std::experimental::nullopt_t;
    using in_place_t = std::experimental::in_place_t;

    constexpr auto nullopt = std::experimental::nullopt;
    constexpr auto in_place = std::experimental::in_place;

    template<class T>
    constexpr auto make_optional(T && value)
    {
        return std::experimental::make_optional(std::forward<T>(value));
    }
}

#endif


#1 楼

@Jerry答案的修改:

#pragma once

#if __has_include(<optional>)

#   include <optional>
namespace stdx {
  using namespace ::std;
}
#elif __has_include(<experimental/optional>)
#   include <experimental/optional>
namespace stdx {
  using namespace ::std;
  using namespace ::std::experimental;
}

#else
#   error <experimental/optional> and <optional> not found
#endif


这具有以下优点:同一命名空间可用于所有“实验”功能(stdx)。

所以stdx::optionalstdx::variant都可以。程序不良。

评论


\ $ \ begingroup \ $
为什么要使用命名空间:: std;在第二种情况下(使用)?另外,为什么在名称空间前面加上::?对我来说似乎没有必要。
\ $ \ endgroup \ $
–贾斯汀
16 Jul 30'2:09



\ $ \ begingroup \ $
@justin因为我想最大程度地减少实验性/可选性与不存在的情况之间的差异。为什么以::为前缀?如果有名称空间std :: std或std :: experimental :: std或其他名称:我想保持明确。否则使用命名空间std;在使用命名空间std之后;可能使用std :: std,这是意外的。我们正在做奇怪的魔咒,我会变得偏执。
\ $ \ endgroup \ $
– ak牛
16年7月30日在2:21

#2 楼

尽管对它们的操作有一定的限制(有时很烦人),但乍看之下它们似乎不适用于此处,因此我至少尝试使用名称空间别名:

#pragma once

#if __has_include(<optional>)

#   include <optional>
    using namespace opt = std;

#elif __has_include(<experimental/optional>)
#   include <experimental/optional>

    using namespace opt = std::experimental;

#else
#   error Must have an optional type, either from <optional> or if not supported from <experimental/optional>.
#endif


然后从这一点开始,您只需使用:opt::whatever,然后视情况将其映射到std::whateverstd::experimental::whatever

评论


\ $ \ begingroup \ $
* facepalm *。这就是为什么我需要代码审查
\ $ \ endgroup \ $
–贾斯汀
16年7月29日在23:59



\ $ \ begingroup \ $
如果我尝试使用std :: optional以外的其他实验类型,这不会引起问题吗? opt :: any ...似乎有点怪异,我猜然后名称空间应该确实是stdext或类似的东西。
\ $ \ endgroup \ $
–贾斯汀
16年7月30日在0:02

\ $ \ begingroup \ $
@Justin:是的,您可能从我最初发布的内容中可以猜到,我首先使用名称空间stdex = ...,然后(部分地)将其切换为使用问题中的opt。您可以很好地定义stdext(或其他)和opt,并在适当时使用它们(即使它们在本质上是彼此同义的)。不太确定后者是否是一个好主意。
\ $ \ endgroup \ $
–杰里·科芬(Jerry Coffin)
16 Jul 30'0:07



\ $ \ begingroup \ $
名称空间stdx {使用名称空间:: std;使用命名空间:: std :: experimental; }可以,不是吗?
\ $ \ endgroup \ $
– ak牛
16年7月30日在1:27

\ $ \ begingroup \ $
@Yakk这将要求同时定义std和std :: experimental,但我不明白为什么这样不起作用:命名空间std {命名空间实验性{}}命名空间stdx使用命名空间std :: experimental; }。想知道std和std :: experimental之间是否有任何冲突。
\ $ \ endgroup \ $
–贾斯汀
16年7月30日在1:54



#3 楼

与其他答案类似,但只是可选的,而没有引入其余的std :: experimental。顺便说一下,我们在真实的代码库中使用了此代码:

#pragma once

#if __has_include(<optional>)

#include <optional>
namespace stdx {
    using std::optional;
    using std::nullopt_t;
    using std::in_place_t;
    using std::bad_optional_access;
    using std::nullopt;
    using std::in_place;
    using std::make_optional;
}

#elif __has_include(<experimental/optional>)

#include <experimental/optional>
namespace stdx {
    using std::experimental::optional;
    using std::experimental::nullopt_t;
    using std::experimental::in_place_t;
    using std::experimental::bad_optional_access;
    using std::experimental::nullopt;
    using std::experimental::in_place;
    using std::experimental::make_optional;
}

#else
    #error "an implementation of optional is required!"
#endif