HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Seamlessly migrating <experimental/optional> to <optional>

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
seamlesslyoptionalmigratingexperimental

Problem

From this Stack Overflow answer, I learned that C++17 will have __has_include, which can


[make] migrating from experimental to std almost seamless

This still leaves the question of how to do it. Doing something like namespace std { using namespace std::experimental; } is undefined behaviour, so I came up with this method:

optional.h demonstration on coliru

#pragma once

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

#if defined HAS_STD_OPTIONAL

namespace opt {
    template
    using optional = std::optional;
    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
    constexpr auto make_optional(T && value)
    {
        return std::make_optional(std::forward(value));
    }
}

#elif defined HAS_STD_EXPERIMENTAL_OPTIONAL

namespace opt {
    template
    using optional = std::experimental::optional;
    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
    constexpr auto make_optional(T && value)
    {
        return std::experimental::make_optional(std::forward(value));
    }
}

#endif

Solution

A modification of @Jerry's answer:

#pragma once

#if __has_include()

#   include 
namespace stdx {
  using namespace ::std;
}
#elif __has_include()
#   include 
namespace stdx {
  using namespace ::std;
  using namespace ::std::experimental;
}

#else
#   error  and  not found
#endif


this has the advantage that the same namespace can be used for all "experimental" features (stdx).

So stdx::optional and stdx::variant both work.

We have to only using namespace ::std::experimental; after at least one <experimental/ header is included, as if it does not exist that is ill formed, and introducing one ourselves also makes the program ill formed.

Code Snippets

#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

Context

StackExchange Code Review Q#136350, answer score: 13

Revisions (0)

No revisions yet.