diff --git a/SingleSource/UnitTests/TypeTraits.cpp b/SingleSource/UnitTests/TypeTraits.cpp new file mode 100644 index 000000000..b5d948660 --- /dev/null +++ b/SingleSource/UnitTests/TypeTraits.cpp @@ -0,0 +1,843 @@ +#include +#include +#include + +namespace conditional_test { + +typedef std::conditional::type Type1; +typedef std::conditional::type Type2; +static_assert(std::is_same_v && std::is_same_v, + "conditional"); +} // namespace conditional_test + +namespace is_same_test { +typedef std::integral_constant two_t; +typedef std::integral_constant four_t; + +static_assert(!std::is_same::value, + "two_t and four_t are not equal!"); + +static_assert(two_t::value * 2 == four_t::value, "2*2 != 4"); +enum class my_e { e1, e2 }; + +typedef std::integral_constant my_e_e1; +typedef std::integral_constant my_e_e2; +static_assert(my_e_e1() == my_e::e1 && my_e_e1::value != my_e::e2 && + std::is_same::value, + "is_same"); +} // namespace is_same_test + +namespace is_base_of_test { +class A {}; +class B : A {}; +class C : B {}; +class D {}; + +static_assert(std::is_base_of_v && std::is_base_of_v && + std::is_base_of_v && !std::is_base_of_v && + !std::is_base_of_v && !std::is_base_of_v, + "is_base_of"); +} // namespace is_base_of_test + +namespace is_convertible_test { +class E { +public: + template E(T &&) {} +}; + +class A {}; +class B : public A {}; +class C {}; +class D { +public: + operator C() { return c; } + C c; +}; + +static_assert(std::is_convertible_v && + !std::is_convertible_v && + std::is_convertible_v && + !std::is_convertible_v && + std::is_convertible_v, + "is_convertible"); +} // namespace is_convertible_test + +namespace is_invocable_test { +auto func2(char) -> int (*)() { return nullptr; } +static_assert(std::is_invocable_v && !std::is_invocable_v && + std::is_invocable_r_v && + !std::is_invocable_r_v && + std::is_invocable_r_v && + !std::is_invocable_r_v && + std::is_invocable_r_v && + !std::is_invocable_r_v, + "is_invocable"); +} // namespace is_invocable_test + +namespace is_void_test { +static_assert(std::is_void::value && !std::is_void::value, + "is_void"); +} + +namespace is_null_pointer_test { +static_assert(std::is_null_pointer::value && + !std::is_null_pointer::value, + "is_null_pointer"); +} + +namespace is_integral_test { +class A { +public: + enum E {}; + int fun() const; +}; +enum E : int {}; +static_assert(!std::is_integral::value && !std::is_integral_v && + !std::is_integral_v && std::is_integral_v && + std::is_integral_v && std::is_integral_v, + "is_integral"); +} // namespace is_integral_test + +namespace is_floating_point_test { +static_assert(!std::is_floating_point::value && + std::is_floating_point::value && + !std::is_floating_point::value && + std::is_floating_point::value && + !std::is_floating_point::value && + !std::is_floating_point::value, + "is_floating_point"); +} + +namespace is_array_test { +static_assert(!std::is_array::value && + std::is_array::value && + std::is_array::value && + !std::is_array::value && !std::is_array::value && + std::is_array::value && std::is_array::value, + "is_array"); +} + +namespace is_enum_test { +enum class Ec : int {}; + +static_assert(!std::is_enum::value && + std::is_enum::value && + std::is_enum() && + !std::is_enum_v && std::is_enum_v, + "is_enum"); +} // namespace is_enum_test + +namespace is_union_test { +union U { + int a; + float b; + class UC {}; +}; + +struct C { + U d; +}; + +static_assert(!std::is_union::value && + std::is_union::value && !std::is_union::value && + !std::is_union::value, + "is_union"); +} // namespace is_union_test + +namespace is_class_test { +struct B {}; + +static_assert(!std::is_class_v && + std::is_class_v && + std::is_class::value && + std::is_class_v && !std::is_class_v && + !std::is_class_v && std::is_class_v && + !std::is_class::value && + !std::is_class_v && std::is_class_v && + std::is_class_v, + "is_class"); +} // namespace is_class_test + +namespace is_function_test { +int f(); +template struct PM_traits {}; +template struct PM_traits { using member_type = U; }; + +using T = PM_traits::member_type; // T is + // int() + +static_assert(!std::is_function::value && + std::is_function::value && + std::is_function::value && + !std::is_function::value && std::is_function::value && + std::is_function::value, + "is_function"); + +} // namespace is_function_test + +namespace is_pointer_test { +static_assert(!std::is_pointer::value && + !std::is_pointer_v && + !std::is_pointer() && + !std::is_pointer{} && + !std::is_pointer()() && + !std::is_pointer{}() && + std::is_pointer::value && + std::is_pointer() && + !std::is_pointer::value && + !std::is_pointer::value && + std::is_pointer::value && + std::is_pointer::value && + !std::is_pointer::value && + !std::is_pointer::value, + "is_pointer"); +} + +namespace is_lvalue_reference_test { +static_assert(!std::is_lvalue_reference::value && + std::is_lvalue_reference_v && + !std::is_lvalue_reference::value && + !std::is_lvalue_reference::value && + std::is_lvalue_reference::value && + !std::is_lvalue_reference::value, + "is_lvalue_reference"); +} + +namespace is_rvalue_reference_test { +static_assert(!std::is_rvalue_reference_v && + !std::is_rvalue_reference_v && + std::is_rvalue_reference_v && + !std::is_rvalue_reference_v && + !std::is_rvalue_reference_v && + std::is_rvalue_reference_v, + "is_rvalue_reference"); +} + +namespace is_member_object_pointer_test { +static_assert( + std::is_member_object_pointer_v && + !std::is_member_object_pointer::value, + "is_member_object_pointer"); +} + +namespace is_member_function_pointer_test { +static_assert( + std::is_member_function_pointer_v && + !std::is_member_function_pointer::value, + "is_member_function_pointer"); +} + +namespace is_fundamental_test { +static_assert(!std::is_fundamental::value && + std::is_fundamental::value && + !std::is_fundamental_v && + !std::is_fundamental::value && + std::is_fundamental::value && + !std::is_fundamental::value && + !std::is_fundamental::value, + "is_fundamental"); +} + +namespace is_arithmetic_test { +static_assert( + !std::is_arithmetic_v && std::is_arithmetic_v && + std::is_arithmetic_v && std::is_arithmetic_v && + !std::is_arithmetic_v && !std::is_arithmetic_v && + std::is_arithmetic_v && std::is_arithmetic_v && + !std::is_arithmetic_v && !std::is_arithmetic_v && + std::is_arithmetic_v && std::is_arithmetic_v && + !std::is_arithmetic_v && !std::is_arithmetic_v && + !std::is_arithmetic::value, + "is_arithmetic"); +} + +namespace is_scalar_test { +static_assert(std::is_scalar_v && std::is_scalar_v && + std::is_scalar_v && + std::is_scalar::value && + std::is_scalar_v && + std::is_scalar_v && + !std::is_scalar_v, + "is_scalar"); +} + +namespace is_object_test { +static_assert(std::is_object_v && !std::is_object::value && + std::is_object::value && + !std::is_object::value, + "is_object"); +} + +namespace is_compound_test { +static_assert(std::is_compound::value && + !std::is_compound_v, + "is_compount"); +} + +namespace is_reference_test { +static_assert(!std::is_reference_v && + std::is_reference_v && + std::is_reference_v && + !std::is_reference_v && std::is_reference_v && + std::is_reference_v && + !std::is_reference_v && + std::is_reference_v && + std::is_reference_v, + "is_reference"); +} + +namespace is_member_pointer_test { +static_assert(std::is_member_pointer::value && + !std::is_member_pointer::value, + "is_member_pointer"); +} + +namespace is_const_test { +static_assert(!std::is_const_v && std::is_const_v && + !std::is_const_v && + std::is_const_v && + !std::is_const_v && + std::is_const_v>, + "is_const"); +} + +namespace is_volatile_test { +static_assert(!std::is_volatile::value && + std::is_volatile::value, + "is_volatile"); +} + +namespace is_trivial_test { +struct Nt { + Nt() {} +}; + +static_assert(std::is_trivial::value && + !std::is_trivial::value, + "is_trivial"); +} // namespace is_trivial_test + +namespace is_trivially_copyable_test { +struct Ntc { + Ntc(Ntc const &) {} +}; + +struct V { + virtual void foo(); +}; + +struct Tc { + int m; + + Tc(Tc const &) = default; // -> trivially copyable + Tc(int x) : m(x + 1) {} +}; + +static_assert(std::is_trivially_copyable::value && + !std::is_trivially_copyable::value && + !std::is_trivially_copyable::value && + std::is_trivially_copyable::value, + "is_trivially_copyable"); +} // namespace is_trivially_copyable_test + +namespace is_standard_layout_test { +struct Nsl { + int m1; + +private: + int m2; +}; + +static_assert( + std::is_standard_layout_v && + !std::is_standard_layout::value && + !std::is_standard_layout::value, + "is_standard_layout"); +} // namespace is_standard_layout_test + +namespace has_unique_object_representation_test { +struct foo { + char c; + float f; + short st; + int i; +}; + +struct bar { + int a; + int b; +}; + +static_assert(!std::has_unique_object_representations_v && + std::has_unique_object_representations_v, + "has_unique_object_representation"); +} // namespace has_unique_object_representation_test + +namespace is_empty_test { +struct NotEmpty { + int m; +}; + +struct StaticMember { + static int m; +}; + +union EmptyUnion {}; + +static_assert(std::is_empty_v && + !std::is_empty::value && + std::is_empty::value && + !std::is_empty::value && + !std::is_empty::value, + "is_empty"); +} // namespace is_empty_test + +namespace is_polymorphic_test { +struct InheritP : is_trivially_copyable_test::V {}; + +struct Dtor { + virtual ~Dtor() = default; +}; + +static_assert(!std::is_polymorphic_v && + std::is_polymorphic::value && + std::is_polymorphic::value && + std::is_polymorphic::value, + "is_polymorphic"); +} // namespace is_polymorphic_test + +namespace is_abstract_test { +struct Abstract { + virtual void foo() = 0; +}; + +struct InheritAbstract : Abstract {}; + +static_assert(!std::is_abstract_v && + !std::is_abstract::value && + std::is_abstract::value && + std::is_abstract::value, + "is_abstract"); +} // namespace is_abstract_test + +namespace is_final_test { +class F final {}; + +static_assert(!std::is_final_v && std::is_final::value, + "is_final"); +} // namespace is_final_test + +namespace is_aggregate_test { +struct NonAggregate { + NonAggregate(int, const char *) {} +}; + +constexpr void is_aggregate_test() { + static_assert( + std::is_aggregate_v && + !std::is_aggregate::value, + "is_aggregate"); +} +} // namespace is_aggregate_test + +namespace is_signed_test { +static_assert(!std::is_signed_v && + std::is_signed_v && std::is_signed_v && + !std::is_signed_v && + !std::is_signed_v && + !std::is_signed_v && + !std::is_signed_v, + "is_signed"); +} + +namespace is_unsigned_test { +enum UEnum : unsigned {}; +enum class UEnumC : unsigned {}; + +static_assert(!std::is_unsigned_v && + !std::is_unsigned_v && + !std::is_unsigned_v && + std::is_unsigned_v && + !std::is_unsigned_v && !std::is_unsigned_v, + "is_unsigned"); +} // namespace is_unsigned_test + +namespace decay_test { +static_assert(std::is_same_v, int> && + std::is_same_v, int> && + std::is_same_v, int> && + std::is_same_v, int> && + std::is_same_v, int *> && + std::is_same_v, int (*)(int)>, + "decay"); +} + +namespace add_reference_test { +using nonref = int; +using lref = std::add_lvalue_reference_t; +using rref = std::add_rvalue_reference_t; +using voidref = std::add_lvalue_reference_t; + +static_assert(!std::is_lvalue_reference_v && + std::is_lvalue_reference_v && + std::is_rvalue_reference_v && + !std::is_reference_v, + "add_reference"); +} // namespace add_reference_test + +namespace remove_extent_test { +constexpr int a[][3] = {{1, 2, 3}, {4, 5, 6}}; +constexpr int b[3] = {7, 8, 9}; +static_assert( + std::is_same_v, const int> && + std::is_same_v, const int[3]>, + "remove_extent"); +} // namespace remove_extent_test + +namespace remove_all_extents_test { + +struct X { + int m; +}; + +static_assert( + std::is_same_v, float> && + std::is_same_v, float> && + std::is_same_v, + float> && + std::is_same_v, float *> && + std::is_same_v, int> && + std::is_same_v, double> && + std::is_same_v, X>, + "remove_all_extents"); +} // namespace remove_all_extents_test + +namespace remove_pointer_test { +static_assert( + std::is_same_v::type> && + std::is_same_v::type> && + !std::is_same_v::type> && + std::is_same_v::type> && + std::is_same_v::type> && + std::is_same_v::type>, + "remove_pointer"); +} + +namespace add_pointer_test { + +template +constexpr void ptr_to_member_func_cvref_test(F Class::*) { + // F is an "abominable function type" + using FF = std::add_pointer_t; + static_assert(std::is_same_v, "FF should be precisely F"); +} + +struct S { + void f_ref() & {} + void f_const() const {} +}; + +constexpr void test() { + int i = 123; + int &ri = i; + typedef std::add_pointer_t IntPtr; + typedef std::add_pointer_t IntPtr2; + + ptr_to_member_func_cvref_test(&S::f_ref); + ptr_to_member_func_cvref_test(&S::f_const); + + static_assert(std::is_pointer_v && std::is_same_v && + std::is_same_v, + "add_pointer"); +} +} // namespace add_pointer_test + +namespace make_signed_test { +static_assert( + std::is_same_v, signed char> && + std::is_same_v, signed int> && + std::is_same_v, + volatile signed long>, + "make_signed"); +} + +namespace make_unsigned_test { +static_assert( + std::is_same::type, unsigned char>::value && + std::is_same::type, unsigned int>::value && + std::is_same::type, + volatile unsigned long>::value, + "make_unsigned"); +} // namespace make_unsigned_test + +namespace is_constructible_test { +class Foo { + int v1; + double v2; + +public: + Foo(int n) : v1(n), v2() {} + Foo(int n, double f) noexcept : v1(n), v2(f) {} +}; + +static_assert(std::is_trivially_constructible_v && + !std::is_trivially_constructible_v && + std::is_constructible_v && + !std::is_nothrow_constructible_v && + std::is_nothrow_constructible_v, + "is_constructible"); +} // namespace is_constructible_test + +namespace is_default_constructible_test { +struct Ex1 { + is_trivial_test::Nt nt; // member has a non-trivial default ctor +}; +struct Ex2 { + int n; + Ex2() = default; // trivial and non-throwing +}; + +static_assert(std::is_default_constructible_v && + !std::is_trivially_default_constructible_v && + std::is_trivially_default_constructible_v && + std::is_nothrow_default_constructible_v, + "is_default_constructible"); +} // namespace is_default_constructible_test + +namespace is_copy_constructible_test { + +struct Ex1 { + is_trivially_copyable_test::Ntc ntc; // member has a non-trivial copy ctor +}; +struct Ex2 { + int n; + Ex2(const Ex2 &) = default; // trivial and non-throwing +}; + +static_assert(std::is_copy_constructible_v && + !std::is_trivially_copy_constructible_v && + std::is_trivially_copy_constructible_v && + std::is_nothrow_copy_constructible_v, + "is_copy_constructible"); +} // namespace is_copy_constructible_test + +namespace is_move_constructible_test { + +struct NonTrivialNonThrowingMove { + NonTrivialNonThrowingMove(NonTrivialNonThrowingMove &&) noexcept {} +}; + +struct Ex1 { + NonTrivialNonThrowingMove str; +}; + +struct Ex2 { + int n; + Ex2(Ex2 &&) = default; // trivial and non-throwing +}; + +struct NoMove { + NoMove(const NoMove &) {} +}; + +static_assert(std::is_move_constructible_v && + !std::is_trivially_move_constructible_v && + std::is_nothrow_move_constructible_v && + std::is_trivially_move_constructible_v && + std::is_nothrow_move_constructible_v && + std::is_move_constructible_v && + !std::is_nothrow_move_constructible_v, + "is_move_constructible"); +} // namespace is_move_constructible_test + +namespace is_assignable_test { +struct Ex1 { + int n; +}; +static_assert(!std::is_assignable_v && + std::is_assignable_v && + !std::is_assignable_v && + std::is_nothrow_assignable_v && + !std::is_assignable_v && + std::is_trivially_assignable_v, + "is_assignable"); +} // namespace is_assignable_test + +namespace is_copy_assignable_test { +struct Foo { + int n; +}; + +static_assert(std::is_trivially_copy_assignable::value && + !std::is_copy_assignable::value && + std::is_nothrow_copy_assignable::value, + "is_copy_assignable"); +} // namespace is_copy_assignable_test + +namespace is_move_assignable_test { +struct Foo { + int n; +}; + +struct NothrowMove { + NothrowMove &operator=(NothrowMove &&) noexcept { return *this; } +}; + +struct NoMove { + // prevents implicit declaration of default move assignment operator + // however, the class is still move-assignable because its + // copy assignment operator can bind to an rvalue argument + NoMove &operator=(const NoMove &) { return *this; } +}; + +static_assert(std::is_nothrow_move_assignable_v && + !std::is_move_assignable_v && + std::is_trivially_move_assignable_v && + std::is_move_assignable_v && + !std::is_nothrow_move_assignable_v, + "is_move_assignable"); +} // namespace is_move_assignable_test + +namespace is_destructible_test { +struct Destructible { + ~Destructible() noexcept {} +}; + +struct Foo { + Destructible str; + ~Foo() noexcept {}; +}; + +struct Bar { + ~Bar() = default; +}; + +static_assert(std::is_destructible_v && + !std::is_trivially_destructible_v && + std::is_nothrow_destructible() && + std::is_trivially_destructible{}, + "is_destructible"); +} // namespace is_destructible_test + +namespace has_virtual_destructor_test { +struct Foo { + virtual ~Foo(){}; +}; + +struct Bar { + ~Bar() {} +}; + +static_assert(std::has_virtual_destructor_v && + !std::has_virtual_destructor{}, + "has_virtual_destructor"); +} // namespace has_virtual_destructor_test + +namespace alignment_of_test { +struct A {}; +struct B { + std::int8_t p; + std::int16_t q; +}; + +static_assert(std::alignment_of_v == 1, + "alignment_of"); + +/* Leaving this uncommented because I'm not certain if this is the intended alignment for short and int +static_assert(std::alignment_of_v == 2 && + std::alignment_of() == 1 && + std::alignment_of_v == 2, + "alignment_of");*/ +} // namespace alignment_of_test + +namespace rank_test { +static_assert(std::rank{} == 0 && std::rank_v == 1 && + std::rank_v == 2 && std::rank_v == 3, + "rank"); +} + +namespace extent_test { +constexpr int ints[] = {1, 2, 3, 4}; + +static_assert(std::extent_v == 3 && std::extent_v == 3 && + std::extent_v == 4 && + std::extent_v == 0 && + std::extent_v == 0 && std::extent{} == 9 && + std::extent_v == 4, + "extent"); +} // namespace extent_test + +namespace remove_cv_test { + +static_assert( + std::is_same_v, int> && + std::is_same_v, int> && + std::is_same_v, int> && + std::is_same_v, int> && + std::is_same_v, + const volatile int *> && + std::is_same_v, const int *> && + std::is_same_v, int *>, + "remove_cv"); +} + +namespace add_cv_test { +struct foo { + void m() {} + void m() const {} + void m() volatile {} + void m() const volatile {} +}; + +static_assert(std::is_same_v, const foo> && + std::is_same_v, volatile foo> && + std::is_same_v, const volatile foo>, + "add_cv"); +} // namespace add_cv_test + +namespace remove_reference_test { +static_assert( + std::is_same_v> && + std::is_same_v> && + std::is_same_v> && + std::is_same_v>, + "remove_reference"); +} + +namespace common_type_test { + +template struct Number { T n; }; + +template +constexpr Number> operator+(const Number &lhs, + const Number &rhs) { + return {lhs.n + rhs.n}; +} + +constexpr Number i1 = {1}, i2 = {2}; +constexpr Number d1 = {2.3}, d2 = {3.5}; + +static_assert((i1 + i2).n == 3 && (i1 + d2).n == 4.5 && (d1 + i2).n == 4.3 && + (d1 + d2).n == 5.8, + "common_type"); + +} // namespace common_type_test + +namespace underlying_type_test { +enum e1 {}; +enum class e2 {}; +enum class e3 : unsigned {}; +enum class e4 : int {}; + +static_assert(!std::is_same_v, int> && + std::is_same_v, int> && + !std::is_same_v, int> && + std::is_same_v, int>, + "underlying_type"); + +} // namespace underlying_type_test + +int main() +{ + return 0; +} diff --git a/SingleSource/UnitTests/TypeTraits.reference_output b/SingleSource/UnitTests/TypeTraits.reference_output new file mode 100644 index 000000000..ca916d098 --- /dev/null +++ b/SingleSource/UnitTests/TypeTraits.reference_output @@ -0,0 +1 @@ +exit 0