address CI build failure

Issue #300
Previous CI fix didn't work, try with type aliasing instead

Issue #300
This reverts commit c87c0e3975.
gcc 6 ok, msvc 14 choked

Issue #300
noexcept(condition) doesn't seem to work on msvs 2015

Issue #300
Merge remote-tracking branch 'origin/dev-optional-no-default-ctor' into dev-resolve-simple-issues
ensure uniqueness (uglify) and undefine compatibility macro
This commit is contained in:
Crzyrndm 2018-07-10 17:26:34 +12:00
parent 07d648fe8b
commit b004d0863c
2 changed files with 40 additions and 16 deletions

View File

@ -25,6 +25,7 @@
#include <xlnt/xlnt_config.hpp> #include <xlnt/xlnt_config.hpp>
#include <xlnt/utils/exceptions.hpp> #include <xlnt/utils/exceptions.hpp>
#include <type_traits>
namespace xlnt { namespace xlnt {
@ -36,6 +37,26 @@ namespace xlnt {
template <typename T> template <typename T>
class optional class optional
{ {
#if _MSC_VER <= 1900 // v14, visual studio 2015
#define XLNT_NOEXCEPT_VALUE_COMPAT(...) (false)
using ctor_copy_T_noexcept = std::false_type;
using ctor_move_T_noexcept = std::false_type;
using copy_ctor_noexcept = ctor_copy_T_noexcept;
using move_ctor_noexcept = ctor_move_T_noexcept;
using set_copy_noexcept_t = std::false_type;
using set_move_noexcept_t = std::false_type;
using clear_noexcept_t = std::false_type;
#else
#define XLNT_NOEXCEPT_VALUE_COMPAT(...) (__VA_ARGS__)
using ctor_copy_T_noexcept = typename std::conditional<std::is_nothrow_copy_constructible<T>{}, std::true_type, std::false_type>::type;
using ctor_move_T_noexcept = typename std::conditional<std::is_nothrow_move_constructible<T>{}, std::true_type, std::false_type>::type;
using copy_ctor_noexcept = ctor_copy_T_noexcept;
using move_ctor_noexcept = ctor_move_T_noexcept;
using set_copy_noexcept_t = typename std::conditional<std::is_nothrow_copy_constructible<T>{} && std::is_nothrow_assignable<T, T>{}, std::true_type, std::false_type>::type;
using set_move_noexcept_t = typename std::conditional<std::is_nothrow_move_constructible<T>{} && std::is_nothrow_move_assignable<T>{}, std::true_type, std::false_type>::type;
using clear_noexcept_t = typename std::conditional<std::is_nothrow_destructible<T>{}, std::true_type, std::false_type>::type;
#endif
public: public:
/// <summary> /// <summary>
/// Default contructor. is_set() will be false initially. /// Default contructor. is_set() will be false initially.
@ -49,7 +70,7 @@ public:
/// Constructs this optional with a value. /// Constructs this optional with a value.
/// noexcept if T copy ctor is noexcept /// noexcept if T copy ctor is noexcept
/// </summary> /// </summary>
optional(const T &value) noexcept(std::is_nothrow_copy_constructible<T>{}) optional(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(ctor_copy_T_noexcept{}))
: has_value_(true) : has_value_(true)
{ {
new (&storage_) T(value); new (&storage_) T(value);
@ -59,7 +80,7 @@ public:
/// Constructs this optional with a value. /// Constructs this optional with a value.
/// noexcept if T move ctor is noexcept /// noexcept if T move ctor is noexcept
/// </summary> /// </summary>
optional(T &&value) noexcept(std::is_nothrow_move_constructible<T>{}) optional(T &&value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(ctor_move_T_noexcept{}))
: has_value_(true) : has_value_(true)
{ {
new (&storage_) T(std::move(value)); new (&storage_) T(std::move(value));
@ -69,7 +90,7 @@ public:
/// Copy constructs this optional from other /// Copy constructs this optional from other
/// noexcept if T copy ctor is noexcept /// noexcept if T copy ctor is noexcept
/// </summary> /// </summary>
optional(const optional& other) noexcept(std::is_nothrow_copy_constructible<T>{}) optional(const optional &other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(copy_ctor_noexcept{}))
: has_value_(other.has_value_) : has_value_(other.has_value_)
{ {
if (has_value_) if (has_value_)
@ -82,7 +103,7 @@ public:
/// Move constructs this optional from other. Clears the value from other if set /// Move constructs this optional from other. Clears the value from other if set
/// noexcept if T move ctor is noexcept /// noexcept if T move ctor is noexcept
/// </summary> /// </summary>
optional(optional &&other) noexcept(std::is_nothrow_move_constructible<T>{}) optional(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(move_ctor_noexcept{}))
: has_value_(other.has_value_) : has_value_(other.has_value_)
{ {
if (has_value_) if (has_value_)
@ -96,7 +117,7 @@ public:
/// Copy assignment of this optional from other /// Copy assignment of this optional from other
/// noexcept if set and clear are noexcept for T& /// noexcept if set and clear are noexcept for T&
/// </summary> /// </summary>
optional &operator=(const optional &other) noexcept(noexcept(set(std::declval<const T &>())) && noexcept(clear())) optional &operator=(const optional &other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{} && clear_noexcept_t{}))
{ {
if (other.has_value_) if (other.has_value_)
{ {
@ -113,7 +134,7 @@ public:
/// Move assignment of this optional from other /// Move assignment of this optional from other
/// noexcept if set and clear are noexcept for T&& /// noexcept if set and clear are noexcept for T&&
/// </summary> /// </summary>
optional &operator=(optional &&other) noexcept(noexcept(set(std::declval<T&&>())) && noexcept(clear())) optional &operator=(optional &&other) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{} && clear_noexcept_t{}))
{ {
if (other.has_value_) if (other.has_value_)
{ {
@ -147,7 +168,7 @@ public:
/// <summary> /// <summary>
/// Copies the value into the stored value /// Copies the value into the stored value
/// </summary> /// </summary>
void set(const T &value) noexcept(std::is_nothrow_copy_constructible<T>{} && std::is_nothrow_assignable<T, T>{}) void set(const T &value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{}))
{ {
if (has_value_) if (has_value_)
{ {
@ -163,7 +184,7 @@ public:
/// <summary> /// <summary>
/// Moves the value into the stored value /// Moves the value into the stored value
/// </summary> /// </summary>
void set(T &&value) noexcept(std::is_nothrow_move_constructible<T>{} && std::is_nothrow_move_assignable<T>{}) void set(T &&value) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{}))
{ {
// note seperate overload for two reasons (as opposed to perfect forwarding) // note seperate overload for two reasons (as opposed to perfect forwarding)
// 1. have to deal with implicit conversions internally with perfect forwarding // 1. have to deal with implicit conversions internally with perfect forwarding
@ -183,7 +204,7 @@ public:
/// <summary> /// <summary>
/// Assignment operator overload. Equivalent to setting the value using optional::set. /// Assignment operator overload. Equivalent to setting the value using optional::set.
/// </summary> /// </summary>
optional &operator=(const T &rhs) noexcept(noexcept(set(std::declval<const T &>()))) optional &operator=(const T &rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_copy_noexcept_t{}))
{ {
set(rhs); set(rhs);
return *this; return *this;
@ -192,7 +213,7 @@ public:
/// <summary> /// <summary>
/// Assignment operator overload. Equivalent to setting the value using optional::set. /// Assignment operator overload. Equivalent to setting the value using optional::set.
/// </summary> /// </summary>
optional &operator=(T &&rhs) noexcept(noexcept(set(std::declval<T &&>()))) optional &operator=(T &&rhs) noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(set_move_noexcept_t{}))
{ {
set(std::move(rhs)); set(std::move(rhs));
return *this; return *this;
@ -201,7 +222,7 @@ public:
/// <summary> /// <summary>
/// After this is called, is_set() will return false until a new value is provided. /// After this is called, is_set() will return false until a new value is provided.
/// </summary> /// </summary>
void clear() noexcept(std::is_nothrow_destructible<T>{}) void clear() noexcept(XLNT_NOEXCEPT_VALUE_COMPAT(clear_noexcept_t{}))
{ {
if (has_value_) if (has_value_)
{ {
@ -268,12 +289,12 @@ public:
private: private:
// helpers for getting a T out of storage // helpers for getting a T out of storage
T & value_ref() T &value_ref() noexcept
{ {
return *reinterpret_cast<T *>(&storage_); return *reinterpret_cast<T *>(&storage_);
} }
const T &value_ref() const const T &value_ref() const noexcept
{ {
return *reinterpret_cast<const T *>(&storage_); return *reinterpret_cast<const T *>(&storage_);
} }
@ -282,4 +303,8 @@ private:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_;
}; };
} // namespace xlnt #ifdef XLNT_NOEXCEPT_VALUE_COMPAT
#undef XLNT_NOEXCEPT_VALUE_COMPAT
#endif
} // namespace xlnt

View File

@ -21,9 +21,8 @@
// @license: http://www.opensource.org/licenses/mit-license.php // @license: http://www.opensource.org/licenses/mit-license.php
// @author: see AUTHORS file // @author: see AUTHORS file
#pragma once
#include <xlnt/xlnt.hpp> #include <xlnt/xlnt.hpp>
#include <xlnt/utils/optional.hpp>
#include <helpers/test_suite.hpp> #include <helpers/test_suite.hpp>
// test helpers // test helpers