Restrict etl::atomic for general types (#1359)

* Print test names at test time (#1343)

* Restrict etl::atomic for general types

Needs adding is_copy_assignable and is_move_assignable, and
adjustments to is_trivially_copyable and is_assignable

* Resolve mutable T value vs. volatile qualified methods

* Remove volatile method overloads

They are deprecated in C++20 because they don't work as users expect anyway.

MSVC hinted for this.

---------

Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
Roland Reichwein 2026-03-26 10:46:20 +01:00 committed by GitHub
parent 31b87b5419
commit 2f242e37f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 406 additions and 181 deletions

View File

@ -807,6 +807,13 @@ namespace etl
{
public:
ETL_STATIC_ASSERT((etl::is_trivially_copyable<T>::value), "atomic<T> requires that T is trivially copyable");
ETL_STATIC_ASSERT((etl::is_copy_constructible<T>::value), "atomic<T> requires that T is copy constructible");
ETL_STATIC_ASSERT((etl::is_copy_assignable<T>::value), "atomic<T> requires that T is copy assignable");
ETL_STATIC_ASSERT((etl::is_move_constructible<T>::value), "atomic<T> requires that T is move constructible");
ETL_STATIC_ASSERT((etl::is_move_assignable<T>::value), "atomic<T> requires that T is move assignable");
ETL_STATIC_ASSERT((etl::is_same<T, typename etl::remove_cv<T>::type>::value), "atomic<T> requires that T is not const or volatile");
atomic()
: flag(0)
, value(T())
@ -827,13 +834,6 @@ namespace etl
return v;
}
T operator =(T v) volatile
{
store(v);
return v;
}
// Conversion operator
operator T () const
{
@ -844,26 +844,12 @@ namespace etl
return result;
}
operator T() volatile const
{
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Is lock free?
bool is_lock_free() const
{
return false;
}
bool is_lock_free() const volatile
{
return false;
}
// Store
void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -873,25 +859,6 @@ namespace etl
ETL_BUILTIN_UNLOCK;
}
void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
(void)order;
ETL_BUILTIN_LOCK;
value = v;
ETL_BUILTIN_UNLOCK;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
{
(void)order;
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const
{
@ -915,17 +882,6 @@ namespace etl
return result;
}
T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
(void)order;
ETL_BUILTIN_LOCK;
T result = value;
value = v;
ETL_BUILTIN_UNLOCK;
return result;
}
// Compare exchange weak
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -947,26 +903,6 @@ namespace etl
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
bool result;
(void)order;
ETL_BUILTIN_LOCK;
if (memcmp(&value, &expected, sizeof(T)) == 0)
{
value = desired;
result = true;
}
else
{
result = false;
}
ETL_BUILTIN_UNLOCK;
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
(void)success;
@ -974,13 +910,6 @@ namespace etl
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
(void)success;
(void)failure;
return compare_exchange_weak(expected, desired);
}
// Compare exchange strong
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -988,12 +917,6 @@ namespace etl
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
(void)order;
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
(void)success;
@ -1001,15 +924,11 @@ namespace etl
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
(void)success;
(void)failure;
return compare_exchange_weak(expected, desired);
}
private:
atomic& operator =(const atomic&) ETL_DELETE;
atomic& operator =(const atomic&) volatile ETL_DELETE;
mutable char flag;
mutable T value;
};
@ -1995,6 +1914,13 @@ namespace etl
{
public:
ETL_STATIC_ASSERT((etl::is_trivially_copyable<T>::value), "atomic<T> requires that T is trivially copyable");
ETL_STATIC_ASSERT((etl::is_copy_constructible<T>::value), "atomic<T> requires that T is copy constructible");
ETL_STATIC_ASSERT((etl::is_copy_assignable<T>::value), "atomic<T> requires that T is copy assignable");
ETL_STATIC_ASSERT((etl::is_move_constructible<T>::value), "atomic<T> requires that T is move constructible");
ETL_STATIC_ASSERT((etl::is_move_assignable<T>::value), "atomic<T> requires that T is move assignable");
ETL_STATIC_ASSERT((etl::is_same<T, typename etl::remove_cv<T>::type>::value), "atomic<T> requires that T is not const or volatile");
atomic()
: flag(0)
, value(T())
@ -2015,13 +1941,6 @@ namespace etl
return v;
}
T operator =(T v) volatile
{
store(v);
return v;
}
// Conversion operator
operator T () const
{
@ -2032,26 +1951,12 @@ namespace etl
return result;
}
operator T() volatile const
{
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Is lock free?
bool is_lock_free() const
{
return false;
}
bool is_lock_free() const volatile
{
return false;
}
// Store
void store(T v, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -2060,23 +1965,6 @@ namespace etl
ETL_BUILTIN_UNLOCK;
}
void store(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
ETL_BUILTIN_LOCK;
value = v;
ETL_BUILTIN_UNLOCK;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const volatile
{
ETL_BUILTIN_LOCK;
T result = value;
ETL_BUILTIN_UNLOCK;
return result;
}
// Load
T load(etl::memory_order order = etl::memory_order_seq_cst) const
{
@ -2098,16 +1986,6 @@ namespace etl
return result;
}
T exchange(T v, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
ETL_BUILTIN_LOCK;
T result = value;
value = v;
ETL_BUILTIN_UNLOCK;
return result;
}
// Compare exchange weak
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
@ -2128,58 +2006,27 @@ namespace etl
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
bool result;
ETL_BUILTIN_LOCK;
if (memcmp(&value, &expected, sizeof(T)) == 0)
{
value = desired;
result = true;
}
else
{
result = false;
}
ETL_BUILTIN_UNLOCK;
return result;
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_weak(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
return compare_exchange_weak(expected, desired);
}
// Compare exchange strong
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst)
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order order = etl::memory_order_seq_cst) volatile
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure)
{
return compare_exchange_weak(expected, desired);
}
bool compare_exchange_strong(T& expected, T desired, etl::memory_order success, etl::memory_order failure) volatile
{
return compare_exchange_weak(expected, desired);
}
private:
atomic& operator =(const atomic&) ETL_DELETE;
atomic& operator =(const atomic&) volatile ETL_DELETE;
mutable char flag;
mutable T value;
};

View File

@ -1929,6 +1929,16 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
using is_move_constructible = std::is_move_constructible<T>;
//*********************************************
// is_copy_assignable
template <typename T>
using is_copy_assignable = std::is_copy_assignable<T>;
//*********************************************
// is_move_assignable
template <typename T>
using is_move_assignable = std::is_move_assignable<T>;
//*********************************************
// is_trivially_constructible
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
@ -1974,6 +1984,9 @@ typedef integral_constant<bool, true> true_type;
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
template <typename T>
using is_trivially_copyable = std::is_trivially_copyable<T>;
#elif ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
template <typename T>
using is_trivially_copyable = etl::bool_constant<__is_trivially_copyable(T)>;
#else
template <typename T>
using is_trivially_copyable = etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>;
@ -2033,6 +2046,29 @@ typedef integral_constant<bool, true> true_type;
{
};
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
//*********************************************
// is_move_assignable
#if ETL_USING_CPP11
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type, T>
{
};
#endif
#if ETL_USING_CPP11
//*********************************************
// is_trivially_constructible
@ -2107,11 +2143,7 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_trivially_copyable
{
#if defined(ETL_COMPILER_GCC)
static ETL_CONSTANT bool value = __has_trivial_copy(T);
#else
static ETL_CONSTANT bool value = __is_trivially_copyable(T);
#endif
};
#elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS)
@ -2182,6 +2214,32 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_move_constructible<T, false>;
//*********************************************
// is_copy_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_copy_assignable;
template <typename T>
struct is_copy_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_copy_assignable<T, false>;
//*********************************************
// is_move_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_move_assignable;
template <typename T>
struct is_move_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_move_assignable<T, false>;
//*********************************************
// is_trivially_constructible
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
@ -2257,7 +2315,11 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_assignable
template <typename T1, typename T2>
#if ETL_USING_BUILTIN_IS_ASSIGNABLE
struct is_assignable : public etl::bool_constant<__is_assignable(T1, T2)>
#else
struct is_assignable : public etl::bool_constant<(etl::is_arithmetic<T1>::value || etl::is_pointer<T1>::value) && (etl::is_arithmetic<T2>::value || etl::is_pointer<T2>::value)>
#endif
{
};
@ -2311,6 +2373,31 @@ typedef integral_constant<bool, true> true_type;
};
#endif
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
#if ETL_USING_CPP11
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
{
};
#endif
//*********************************************
// is_trivially_constructible
template <typename T>
@ -2342,7 +2429,11 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_trivially_copyable
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
struct is_trivially_copyable : public etl::bool_constant<__is_trivially_copyable(T)>
#else
struct is_trivially_copyable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
@ -2389,6 +2480,12 @@ typedef integral_constant<bool, true> true_type;
template<typename T>
inline constexpr bool is_move_constructible_v = etl::is_move_constructible<T>::value;
template<typename T>
inline constexpr bool is_copy_assignable_v = etl::is_copy_assignable<T>::value;
template<typename T>
inline constexpr bool is_move_assignable_v = etl::is_move_assignable<T>::value;
template <typename T>
inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible<T>::value;

View File

@ -1922,6 +1922,16 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
using is_move_constructible = std::is_move_constructible<T>;
//*********************************************
// is_copy_assignable
template <typename T>
using is_copy_assignable = std::is_copy_assignable<T>;
//*********************************************
// is_move_assignable
template <typename T>
using is_move_assignable = std::is_move_assignable<T>;
//*********************************************
// is_trivially_constructible
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
@ -1967,6 +1977,9 @@ typedef integral_constant<bool, true> true_type;
#if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED
template <typename T>
using is_trivially_copyable = std::is_trivially_copyable<T>;
#elif ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
template <typename T>
using is_trivially_copyable = etl::bool_constant<__is_trivially_copyable(T)>;
#else
template <typename T>
using is_trivially_copyable = etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>;
@ -2026,6 +2039,29 @@ typedef integral_constant<bool, true> true_type;
{
};
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
//*********************************************
// is_move_assignable
#if ETL_USING_CPP11
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type, T>
{
};
#endif
#if ETL_USING_CPP11
//*********************************************
// is_trivially_constructible
@ -2100,11 +2136,7 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_trivially_copyable
{
#if defined(ETL_COMPILER_GCC)
static ETL_CONSTANT bool value = __has_trivial_copy(T);
#else
static ETL_CONSTANT bool value = __is_trivially_copyable(T);
#endif
};
#elif defined(ETL_USER_DEFINED_TYPE_TRAITS) && !defined(ETL_USE_TYPE_TRAITS_BUILTINS)
@ -2175,6 +2207,32 @@ typedef integral_constant<bool, true> true_type;
template <typename T>
struct is_move_constructible<T, false>;
//*********************************************
// is_copy_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_copy_assignable;
template <typename T>
struct is_copy_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_copy_assignable<T, false>;
//*********************************************
// is_move_assignable
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
struct is_move_assignable;
template <typename T>
struct is_move_assignable<T, true> : public etl::true_type
{
};
template <typename T>
struct is_move_assignable<T, false>;
//*********************************************
// is_trivially_constructible
template <typename T, bool BValue = etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
@ -2250,7 +2308,11 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_assignable
template <typename T1, typename T2>
#if ETL_USING_BUILTIN_IS_ASSIGNABLE
struct is_assignable : public etl::bool_constant<__is_assignable(T1, T2)>
#else
struct is_assignable : public etl::bool_constant<(etl::is_arithmetic<T1>::value || etl::is_pointer<T1>::value) && (etl::is_arithmetic<T2>::value || etl::is_pointer<T2>::value)>
#endif
{
};
@ -2304,6 +2366,31 @@ typedef integral_constant<bool, true> true_type;
};
#endif
//*********************************************
// is_copy_assignable
template <typename T>
struct is_copy_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_lvalue_reference<const T>::type>
{
};
#if ETL_USING_CPP11
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::is_assignable<typename etl::add_lvalue_reference<T>::type,
typename etl::add_rvalue_reference<T>::type>
{
};
#else
//*********************************************
// is_move_assignable
template <typename T>
struct is_move_assignable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
{
};
#endif
//*********************************************
// is_trivially_constructible
template <typename T>
@ -2335,7 +2422,11 @@ typedef integral_constant<bool, true> true_type;
//*********************************************
// is_trivially_copyable
template <typename T>
#if ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE
struct is_trivially_copyable : public etl::bool_constant<__is_trivially_copyable(T)>
#else
struct is_trivially_copyable : public etl::bool_constant<etl::is_arithmetic<T>::value || etl::is_pointer<T>::value>
#endif
{
};
@ -2382,6 +2473,12 @@ typedef integral_constant<bool, true> true_type;
template<typename T>
inline constexpr bool is_move_constructible_v = etl::is_move_constructible<T>::value;
template<typename T>
inline constexpr bool is_copy_assignable_v = etl::is_copy_assignable<T>::value;
template<typename T>
inline constexpr bool is_move_assignable_v = etl::is_move_assignable<T>::value;
template <typename T>
inline constexpr bool is_trivially_constructible_v = etl::is_trivially_constructible<T>::value;

View File

@ -711,6 +711,130 @@ namespace
CHECK_EQUAL(compare.load(), test.load());
}
//*************************************************************************
TEST(test_atomic_non_scalar_trivially_copyable_struct)
{
struct Data
{
int x;
int y;
bool operator ==(const Data& other) const
{
return (x == other.x) && (y == other.y);
}
};
// Default construction
etl::atomic<Data> test;
Data d1 = { 1, 2 };
Data d2 = { 3, 4 };
Data d3 = { 5, 6 };
// Store and load
test.store(d1);
Data loaded = test.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
// Assignment operator
test = d2;
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Conversion operator
test.store(d1);
Data converted = static_cast<Data>(test);
CHECK_EQUAL(d1.x, converted.x);
CHECK_EQUAL(d1.y, converted.y);
// Exchange
test.store(d1);
Data old_val = test.exchange(d2);
CHECK_EQUAL(d1.x, old_val.x);
CHECK_EQUAL(d1.y, old_val.y);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Compare exchange weak - pass (expected matches)
test.store(d1);
Data expected = d1;
bool result = test.compare_exchange_weak(expected, d3);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d3.x, loaded.x);
CHECK_EQUAL(d3.y, loaded.y);
// Compare exchange weak - fail (expected does not match)
test.store(d1);
expected = d2;
result = test.compare_exchange_weak(expected, d3);
CHECK_FALSE(result);
loaded = test.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
// Compare exchange weak with two memory order args - pass
test.store(d1);
expected = d1;
result = test.compare_exchange_weak(expected, d2, etl::memory_order_seq_cst, etl::memory_order_seq_cst);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Compare exchange strong - pass (expected matches)
test.store(d1);
expected = d1;
result = test.compare_exchange_strong(expected, d3);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d3.x, loaded.x);
CHECK_EQUAL(d3.y, loaded.y);
// Compare exchange strong - fail (expected does not match)
test.store(d1);
expected = d2;
result = test.compare_exchange_strong(expected, d3);
CHECK_FALSE(result);
loaded = test.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
// Compare exchange strong with two memory order args - pass
test.store(d1);
expected = d1;
result = test.compare_exchange_strong(expected, d2, etl::memory_order_seq_cst, etl::memory_order_seq_cst);
CHECK_TRUE(result);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Explicit memory order on store/load
test.store(d3, etl::memory_order_release);
loaded = test.load(etl::memory_order_acquire);
CHECK_EQUAL(d3.x, loaded.x);
CHECK_EQUAL(d3.y, loaded.y);
// Exchange with explicit memory order
test.store(d1);
old_val = test.exchange(d2, etl::memory_order_acq_rel);
CHECK_EQUAL(d1.x, old_val.x);
CHECK_EQUAL(d1.y, old_val.y);
loaded = test.load();
CHECK_EQUAL(d2.x, loaded.x);
CHECK_EQUAL(d2.y, loaded.y);
// Value construction
etl::atomic<Data> test2(d1);
loaded = test2.load();
CHECK_EQUAL(d1.x, loaded.x);
CHECK_EQUAL(d1.y, loaded.y);
}
//*************************************************************************
#if REALTIME_TEST

View File

@ -210,6 +210,8 @@ using etl::is_assignable;
using etl::is_constructible;
using etl::is_copy_constructible;
using etl::is_move_constructible;
using etl::is_copy_assignable;
using etl::is_move_assignable;
//*************************
template <>
@ -227,6 +229,16 @@ struct etl::is_move_constructible<Copyable> : public etl::false_type
{
};
template <>
struct etl::is_copy_assignable<Copyable> : public etl::true_type
{
};
template <>
struct etl::is_move_assignable<Copyable> : public etl::true_type
{
};
//*************************
template <>
struct etl::is_assignable<Moveable, Moveable> : public etl::true_type
@ -243,6 +255,16 @@ struct etl::is_move_constructible<Moveable> : public etl::true_type
{
};
template <>
struct etl::is_copy_assignable<Moveable> : public etl::false_type
{
};
template <>
struct etl::is_move_assignable<Moveable> : public etl::true_type
{
};
//*************************
template <>
struct etl::is_assignable<MoveableCopyable, MoveableCopyable> : public etl::true_type
@ -258,6 +280,16 @@ template <>
struct etl::is_move_constructible<MoveableCopyable> : public etl::true_type
{
};
template <>
struct etl::is_copy_assignable<MoveableCopyable> : public etl::true_type
{
};
template <>
struct etl::is_move_assignable<MoveableCopyable> : public etl::true_type
{
};
#endif
namespace
@ -1296,6 +1328,34 @@ namespace
#endif
}
//*************************************************************************
TEST(test_is_copy_assignable)
{
#if ETL_USING_CPP17
CHECK((etl::is_copy_assignable_v<Copyable>) == (std::is_copy_assignable_v<Copyable>));
CHECK((etl::is_copy_assignable_v<Moveable>) == (std::is_copy_assignable_v<Moveable>));
CHECK((etl::is_copy_assignable_v<MoveableCopyable>) == (std::is_copy_assignable_v<MoveableCopyable>));
#else
CHECK((etl::is_copy_assignable<Copyable>::value) == (std::is_copy_assignable<Copyable>::value));
CHECK((etl::is_copy_assignable<Moveable>::value) == (std::is_copy_assignable<Moveable>::value));
CHECK((etl::is_copy_assignable<MoveableCopyable>::value) == (std::is_copy_assignable<MoveableCopyable>::value));
#endif
}
//*************************************************************************
TEST(test_is_move_assignable)
{
#if ETL_USING_CPP17
CHECK((etl::is_move_assignable_v<Copyable>) == (std::is_move_assignable_v<Copyable>));
CHECK((etl::is_move_assignable_v<Moveable>) == (std::is_move_assignable_v<Moveable>));
CHECK((etl::is_move_assignable_v<MoveableCopyable>) == (std::is_move_assignable_v<MoveableCopyable>));
#else
CHECK((etl::is_move_assignable<Copyable>::value) == (std::is_move_assignable<Copyable>::value));
CHECK((etl::is_move_assignable<Moveable>::value) == (std::is_move_assignable<Moveable>::value));
CHECK((etl::is_move_assignable<MoveableCopyable>::value) == (std::is_move_assignable<MoveableCopyable>::value));
#endif
}
//*************************************************************************
TEST(test_is_trivially_constructible)
{