Skip to content

ZXShady/extra_traits

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

extra_traits

simple library for some missing type traits I always need when making unreadable meta programs.

Minimum C++11 with support for variadic macros and variaidc templates and type traits library.

all these are available in namespace zxshady::tmp and all type traits have _t unconditionally but it also has _v shortcuts if available.

has_operator_*

each of these has their own header for minimizing includes you can look at the file names at include/zxshady/has_operators/

Category Operator
Increment/Decrement post_increment
pre_decrement
pre_increment
post_increment
Unary dereference
complement
unary_minus
unary_plus
Bitwise bit_and
bit_or
bit_xor
bit_and_assign
bit_or_assign
bit_xor_assign
Shift left_shift
left_shift_assign
right_shift
right_shift_assign
Logical logical_and
logical_not
logical_or
Arithmetic plus
minus
modulus
multiply
divide
plus_assign
minus_assign
modulus_assign
multiply_assign
divide_assign
Comparison equal_to
not_equal_to
less
less_equal
greater
greater_equal
Accessors arrow
subscript
addressof
Functor call

each has_operator_XXX has 4 static members

has_operator_XXX<T>::member; // whether it is a member function
has_operator_XXX<T>::free; // whether it is a free function
has_operator_XXX<T>::overloaded; // equalivent to member || free
has_operator_XXX<T>::value; // whether it has the operator or not

simple type aliases

template<std::size_t Value>
using index_c = std::integral_constant<std::size_t,Value>;

template<typename T>
using alignof_c = std::integral_constant<std::size_t,alignof(T)>;

template<typename T>
using sizeof_c = std::integral_constant<std::size_t,sizeof(T)>;

// this is avaiable in C++17
template<auto Value> 
using constant = std::integral_constant<decltype(Value),Value>;

template<typename Trait>
using t_ = typename Trait::type; // shortcut trait

template<typename Trait>
constexpr bool v_ = Trait::value; // shortcut variable

_
template<typename...>
using always_false = std::false_type; (var alias : false_v)

template<typename...>
using always_true = std::true_type; (var alias: true_v)

template<typename T,typename...>
using type_t = T;

template<typename T> // since C++14
using is_inheritable = bool_constant<std::is_class_v<T> && !std::is_final_v<T> >;

template<typename...>
struct empty_base {};

// does not report true for bool
template<typename T>
using is_signed_integral = std::bool_constant<
!std::is_same_v<bool,std::remove_cv_t<T>> && std::is_integral_v<T> && std::is_signed_v<T>>; 


// does not report true for bool
template<typename T>
using is_unsigned_integral = std::bool_constant<!std::is_same_v<bool,std::remove_cv_t<T>> && std::is_integral_v<T> && std::is_unsigned_v<T>>; 

utility functions

as_const(T&) // same as std::as__const
as_volatile(T&) 
as_cv(T&)
forward_like<Like>(T&)

Standard Library Features in previous C++ versions

// in "extra_traits/standard_library_features.hpp"
std::disjunction
std::conjunction
std::negation
std::is_null_pointer
std::bool_constant
std::type_identity
std::integer_sequence
std::remove_cvref
std::void_t
std::is_scoped_enum
std::is_bounded_array
std::is_unbounded_array

utility traits

 template<bool Condition,typename Base>
 inherit_if<Condition,Base>::type // if Condition is true then inherit from Base otherwise inherit from empty_base<Base>

non-short circuiting disjunction and conjunction

and_<Traits...>::value;
or_<Traits...>::value;

constructing predicates

template<template<class...> class... Predicates>
struct predicate_and;

template<template<class...> class... Predicates>
struct predicate_or;

template<template<class...> class Predicates>
struct predicate_not;

// each one of them has a member called 
// 'invoke' that is used like this
using is_const_integer = predicate_and<std::is_const,std::is_integral>;
static_assert(template is_const_integer::invoke<int>::value);

unary traits

is_scoped_enum<Enum>::value
is_unscoped_enum<Enum>::value

modifying traits

remove_all_pointers<int******> -> int;
remove_all_pointers<float(*)[]> -> float[];

Qualifications Copying and Maniplating Traits

Note each copy_xxxxx trait has a corrosponding clone_xxxxx (except copy_signedness there is no corrosponding clone_signedness) which is equal to copy_xxxxx<From,remove_xxxxx_t<To>>*

copy_const<From,To>

Show Table
From                  -> To
const From            -> const To
volatile From         -> To
const volatile From   -> const To
--------------------------------
From&                 -> To
const From&           -> To
volatile From&        -> To
const volatile From&  -> To
--------------------------------
From&&                -> To
const From&&          -> To
volatile From&&       -> To
const volatile From&& -> To

copy_volatile<From,To>

Show Table
From                  -> To
const From            -> To
volatile From         -> volatile To
const volatile From   -> volatile To
--------------------------------
From&                 -> To
const From&           -> To
volatile From&        -> To
const volatile From&  -> To
--------------------------------
From&&                -> To
const From&&          -> To
volatile From&&       -> To
const volatile From&& -> To

copy_cv<From,To>

is a short cut for copy_const_t <From,copy_volatile_t<From,To>>

Show Table From -> To const From -> const To volatile From -> volatile To const volatile From -> const volatile To -------------------------------- From& -> To const From& -> To volatile From& -> To const volatile From& -> To -------------------------------- From&& -> To const From&& -> To volatile From&& -> To const volatile From&& -> To

copy_reference<From,To>

Show Table

NOTE: this uses reference collapsing rules, which may not be wanted if you do not want it then use clone_reference.

From                  -> To
const From            -> To
volatile From         -> To
const volatile From   -> To
--------------------------------
From&                 -> To&
const From&           -> To&
volatile From&        -> To&
const volatile From&  -> To&
--------------------------------
From&&                -> To&&
const From&&          -> To&&
volatile From&&       -> To&&
const volatile From&& -> To&&

copy_cvref<From,To>

a short cut for "copy_reference<From, copy_reference_t<To, copy_cv_t<remove_reference_t<From>, remove_reference_t<To>>>>"

copy_pointer<From,To>

Show Table
From                  -> To
const From            -> To
volatile From         -> To
const volatile From   -> To
--------------------------------
From*                 -> To*
From*const            -> To*
From*volatile         -> To*
From*const volatile   -> To*

copy_all_pointers<From,To>

Show Table
From                  -> To
const From            -> To
volatile From         -> To
const volatile From   -> To
--------------------------------
From**                 -> To**
From**const            -> To**
From**volatile         -> To**
From**const volatile   -> To**

copy_signedness<From,To>

Show Table
signed From                  -> signed To
const signed From            -> signed To
volatile signed From         -> signed To
const volatile signed From   -> signed To
--------------------------------
unsigned From                  -> unsigned To
const unsigned From            -> unsigned To
volatile unsigned From         -> unsigned To
const volatile unsigned From   -> unsigned To
--------------------------------
char                 -> [to's sign does not change] To
const char           -> [to's sign does not change] To
volatile char        -> [to's sign does not change] To
const volatile char  -> [to's sign does not change] To

least_size_[u]int

gets the smallest unsigned or signed integer type that can hold this value

Show Example (it can differ depending on the size of types)
least_size_uint_t<200>; // unsigned char
least_size_int_t<500>; // signed short 

remove_[l|r]value_reference

removes the reference qualifier if it is an L or R value respectivly.

Show Table
typename remove_lvalue_reference<int>::type; // int
typename remove_lvalue_reference<int&>::type; // int
typename remove_lvalue_reference<int&&>::type; // int&&

typename remove_rvalue_reference<int>::type; // int
typename remove_rvalue_reference<int&>::type; // int&
typename remove_rvalue_reference<int&&>::type; // int

ZXSHADY_FWD ZXSHADY_MOV macros

the first does a std::forward and the second does std::move, why does these exist? well it is for compile time performance as std::forward is relativly expensive for a glorified static_cast these macros fix this issue these macros are in the extra_traits/macros.hpp header file.

Show Example
[](auto&& vals) {
std::forward<decltype(vals)>(vals);
// vs  
ZXSHADY_FWD(vals)

std::move(vals);
// vs
ZXSHADY_MOV(vals);
}

is_explicitly_constructible

tests for whether the type is explicitly constructible given the Args

it also has is_explicitly_default_constructible<T>,is_explicitly_copy_constructible<T> and is_explicitly_move_constructible<T>

using namespace zxshady::tmp;

struct A {
    explicit A(int,int);
    /*implicit*/ A(int,int,int);
};
is_explicitly_constructible<A,int,int>::value; // true
is_explicitly_constructible<A,int,int,int>::value; // false
is_explicitly_constructible<A,char*>::value; // false

is_implicitly_constructible<T,Args...>

the opposite of is_explicitly_constructible<T,Args...> it checks whether the type is implictly constructible

it also has is_implicitly_default_constructible<T>,is_implicitly_copy_constructible<T> and is_implicitly_move_constructible<T>

using namespace zxshady::tmp;

struct A {
    explicit A(int,int);
    /*implicit*/ A(int,int,int);
};
is_implicitly_constructible<A,int,int>::value; // false
is_implicitly_constructible<A,int,int,int>::value; // true
is_implicitly_constructible<A,char*>::value; // false

type_list<Types...>

a container that contains types.

static members

size a static constant equal to `sizeof...(Types)`
using List = type_list<int,char,long>;
static_assert(List::size == 3);

is_empty a static boolean constant equal to size == 0
using List = type_list<int,char,long>;
using List2 = type_list<>;
static_assert(!List::is_empty);
static_assert(List2::is_empty);

at<Index> index into the types from the list. if the index is out of bounds a `static_assert` will fire.
using List = type_list<int,char,long>;
static_assert(std::is_same_v<char,List::template at<1>>);

at_or<Index,OrType> index into the types from the list. if the index is out of bounds then returns the OrType instead of failing.
using List = type_list<int,char,long>;
static_assert(std::is_same_v<long,List::template at_or<2,void>>); 
static_assert(std::is_same_v<void,List::template at_or<5,void>>);

front equal to `List::template at<0>`

note this member does not exist if is_empty is true

using List = type_list<int,char,long>;
static_assert(std::is_same_v<int,List::front>); 

back equal to `List::template at<size-1>`

note this member does not exist if is_empty is true

using List = type_list<int,char,long>;
static_assert(std::is_same_v<long,List::back>); 

operator+ does concatenation of 2 lists
using List1 = type_list<int[1],int[2]>;
using List2 = type_list<int[3],int[4]>;
static_assert(std::is_same_v<decltype(List1{} + List2{}),type_list&gtint[1],int[2],int[3],int[4]&lt>); 

reverse reverses the list
using List = type_list<int,char,long>;
using NewList = List::reverse;
static_assert(std::is_same_v<long,NewList::back>); 
static_assert(std::is_same_v<int,NewList::front>); 

pop_front pops the first type in the list
using List = type_list<int,char,unsigned int,long>;
using NewList = List::pop_front;
static_assert(std::is_same_v<char,NewList::front>); 

pop_back pops the last type in the list
using List = type_list<int,char,unsigned int,long>;
using NewList = List::pop_back;
static_assert(std::is_same_v<unsigned int,NewList::back>); 

transform<TransformTrait> apply the TransformTrait to every type in the list,
using List = type_list<int,char,long>;
static_assert(std::is_same_v<List::template transform<std::add_const>,type_list<const int,const char,const long> >); 

rename_to<Template>
using List = type_list<int,custom_allocator<int>>;

static_assert(std::is_same_v<List::template rename_to<std::vector>,std::vector<int,custom_allocator<int>> >); 

insert<Index,Types...>
using List = type_list<int,char,long>;

static_assert(std::is_same_v<List::template insert<1,unsigned int,void>,type_list<int,char,unsigned int ,void,long> >); 

erase<Index>
using List = type_list<int,void,char>;

static_assert(std::is_same_v<List::template erase<1>,type_list<int,char> >); 

erase_if<Predicate>
using List = type_list<int,const void,char,const long>;

static_assert(std::is_same_v<List::template erase_if<std::is_const>,type_list<int,char> >); 

slice<Begin,End = size>
using List = type_list<int[1],int[2],int[3],int[4]>;

static_assert(std::is_same_v<List::template slice<0>,type_list<int[1],int[2],int[3],int[4]>>); 
static_assert(std::is_same_v<List::template slice<1>,type_list<int[2],int[3],int[4]>>);
static_assert(std::is_same_v<List::template slice<1,2>,type_list<int[1],int[4]>>); 
static_assert(std::is_same_v<List::template slice<4>>,type_list<>>); 

drop_first<Count>
using List = type_list<int[1],int[2],int[3],int[4]>;

static_assert(std::is_same_v<List::template drop_first<0>,type_list<int[1],int[2],int[3],int[4]>>); 
static_assert(std::is_same_v<List::template drop_first<1>,type_list<int[2],int[3],int[4]>>);
static_assert(std::is_same_v<List::template drop_first<2>,type_list<int[3],int[4]>>); 
static_assert(std::is_same_v<List::template drop_first<4>>,type_list<>>); 

drop_last<Count>
using List = type_list<int[1],int[2],int[3],int[4]>;

static_assert(std::is_same_v<List::template drop_last<0>,type_list<int[1],int[2],int[3],int[4]>>); 
static_assert(std::is_same_v<List::template drop_last<1>,type_list<int[1],int[2],int[3]>>);
static_assert(std::is_same_v<List::template drop_last<2>,type_list<int[1],int[2]>>); 
static_assert(std::is_same_v<List::template drop_last<4>>,type_list<>>); 

replace_at<Index,T>
using List = type_list<int,char,long>;


static_assert(std::is_same_v<List::template replace_at<0,void>, type_list<void,char,long>>);
static_assert(std::is_same_v<List::template replace_at<1,void>, type_list<int,void,long>>);
static_assert(std::is_same_v<List::template replace_at<2,void>, type_list<int,char,void>>);

Free Functions

find_if<Predicate,Pos = 0> *note* returns std::size_t(-1) on not found
using List = type_list<int,char,const long,volatile void>;


static_assert(find_if<std::is_const>(List{}) == 2);
static_assert(find_if<std::is_void>(List{}) == 3);

find<T,Pos = 0>
using List = type_list<int,char,long>;


static_assert(find<void>(List{}) == std::size_t(-1));
static_assert(find<char,0>(List{}) == 1);

type_list_repeat_n<N,T> returns a type_list with N Ts in it
static_assert(std::is_same_v<type_list_repeat_n<5, int>, type_list<int, int, int, int, int>>);
static_assert(std::is_same_v<type_list_repeat_n<0, int>, type_list<>>);
static_assert(std::is_same_v<type_list_repeat_n<1, int>, type_list<int>>);

there is still more methods.

documentation incomplete...

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published