Overview

This is a C++ library, created to include algorithms that can be worked out at compile time.
It uses template meta programming and functional programming techniques to execute many algorithms at compile time on one or more types.

The more work done at compile time, less time to complete the job at run time!

All algorithms/features are wrapped in namespace ctl

Features available to use:

Note:

  • Container algorithms and utility are influenced by Boost::MP11.
    This has been started as re-inventing wheel theory and taken personal approach to implement the APIs/Functions that MP11 library supports.
    Many of the algorithms are having the same name as mentioned in library MP11.

  • _t next to algorithm name is implemented to avoid using ::type keyword with algorithm

  • _c next to algorithm name is implemented to take constants which are known at compile time (ex: true/false or numbers)

  • _f next to algorithm name is implemented to take template types as template parameter

  • _p next to algorithm name is implemented to take predicate as template parameter (predicate is a template type). It is same as _f, but _p is used to make it more clear to read

  • _qmf next to algorithm name is implemented to take Quoted meta functions as template parameter

    • _qmf implementations are using its non _qmf counterparts

  • _v next to algorithm name is implemented to get the constant value (boolean or number). it is like using ::value on the integral_constant type

Container

There are 2 parts here.

  • List ⇒ the container which holds the type

  • Algorithms ⇒ used with list type. Not necessarily with ctl::list but any other compile time list as well. ex: std::tuple

List

It is a container which holds the types. It is an heterogenous container.

To use make sure to add #include <container/list.hpp> in source file.

There are 3 variants of list

  • clt::list<> ⇒ non-instantiable list

  • ctl::ilist<> ⇒ instantiable list

  • ctl::clist<> ⇒ instantiable and callable list.
    It has many operator over-loadings which can be called at runtime.
    Example for the same can be found in src/main.cpp file

Many algorithms can be applied on the created list type.
Even algorithms from MP11 can also be used with the list type.

Algorithms

Once the heterogenous list is created, algorithms are required to do some work with that list. like for example, to add new element to existing list, or to retrieve an element, or remove specific entry in the list like or even sorting the types in the list. Just like data structure std::vector<> (note that std::vector<> can be used to hold the values of homogenous type at runtime).

These algorithms can be used with any list of types like std::tuple<>. It is not restricted to ctl::list alone.

To use any algorithms make sure to add #include <container/algorithms.hpp> in source file.

All algorithms will result in new type. original type is never modified

Modifiers

Set of algorithms are used to get the new list from the original list by adding/removing one or more types.

General usage of the algorithm is:

using modified_type = _algo name_<L<Ts...>, U>::type

where,

  • _ algo name _ ⇒ name of the modifiable algorithms listed below

  • L<Ts…​> ⇒ list which has to be modified

  • U ⇒ type of the interest. It could be single type or another list type!
    This is optional parameter depending on algorithm.

  • ::type ⇒ to access the type from the result of the modified list.
    If algorithm name is postfixed with _t then there is no need of using ::type

Following are some of modifiable algorithms (replaced with _ algo name _):

rename

Usage:

using result = ctl::rename<L<Ts...>, Y>::type
if
  `L<Ts...> = ctl::list<T1, T2, T3>`
  `Y == std::tuple`
then
  `result = std::tuple<T2, T3, T1>`

Variants:

  • rename

  • rename_t ⇒ to avoid ::type

apply

Usage:

using result = ctl::apply<Y, L<Ts...>>::type
if
    `Y == std::tuple`
    `L<Ts...> = ctl::list<T1, T2, T3>`
then
    `result = std::tuple<T2, T3, T1>`

Variants:

  • apply ⇒ same as rename but template parameters reversed

  • apply_t ⇒ to avoid ::type

rotate left

Usage:

using result = rotate_left_c<L<Ts...>, _num_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `_num_ = 1`
then
    `result = L<T2, T3, T1>`

Variants:

  • rotate_left_c

  • rotate_left_c_t ⇒ to avoid ::type

  • rotate_leftnum is passed as type (It should have ::value to access the member). ::type is needed to access the type

  • rotate_left_t ⇒ to avoid ::type

rotate right

Usage:

using result = rotate_right_c<L<Ts...>, _num_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `_num_ = 1`
then
    `result = L<T3, T1, T2>`

Variants:

  • rotate_right_c

  • rotate_right_c_t ⇒ to avoid ::type

  • rotate_rightnum is passed as type (It should have ::value to access the member). ::type is needed to access the result type

  • rotate_right_t ⇒ to avoid ::type

sort

Usage:

using result = sort<L<Ts...>>::type
if
    `L<Ts...> = L<T3, T2, T1>`
then
    `result = L<T1, T2, T3>`

where `T1::value <= T2::value <= T3::value`.

Logic used here is Quick sort.

Variants:

  • sort

  • sort_t ⇒ to avoid ::type

  • sort_p ⇒ to provide comparator as predicate to compare 2 types. ::type is needed to access the result type

    • comparator should return true if the first template parameter should be considered before the second template parameter

  • sort_p_t ⇒ to avoid ::type

  • sort_qmf_p ⇒ to provide comparator predicate as quoted meta function. ::type is needed to access the result type

  • sort_qmf_p_t ⇒ to avoid ::type

reverse

Usage:

using result = ctl::reverse<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = L<T3, T2, T1>`

Variants:

  • reverse

  • reverse_t ⇒ to avoid ::type

replace

Usage:

using result = ctl::replace<L<Ts...>, TR, RW>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `TR = T2`
    `RW = T4`
then
    `result = L<T1, T4, T3>`

Variants:

  • replace

  • replace_t ⇒ to avoid ::type

  • replace_at_c ⇒ to replace type at given position (position is a constant). ::type is needed to access the result type

  • replace_at_c_t ⇒ to avoid ::type

  • replace_at ⇒ to replace type at given position (position is a type, ::value is used to access the constant). ::type is needed to access the result type

  • replace_at_t ⇒ to avoid ::type

  • replace_if ⇒ to replace all types which results in true when passed to given predicate. ::type is needed to access the result type

  • replace_if_t ⇒ to avoid ::type

  • replace_if_qmf ⇒ predicate passed as quoted meta function. ::type is needed to access the result type

  • replace_if_qmf_t ⇒ to avoid ::type

push_front

Usage:

using result = ctl::push_front<L<Ts...>, T>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `L<T4, T5, T6>`
then
    `result = L<T4, T5, T6, T1, T2, T3>`

Variants:

  • push_front ⇒ to push another type/list to front of given list

  • push_front_t ⇒ used to avoid ::type

push_back

Usage:

using result = ctl::push_back<L<Ts...>, T>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `L<T4, T5, T6>`
then
    `result = L<T1, T2, T3, T4, T5, T6>`

Variants:

  • push_back ⇒ to push another type/list to back of given list

  • push_back_t ⇒ to avoid ::type

append

Usage:

using result = ctl::append<L<Ts...>, T>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `T = `L<T4, T5, T6>`
then
    `result = L<T1, T2, T3, T4, T5, T6>`

Variants:

  • append ⇒ alias to push_back

  • append_t ⇒ alias to push_back_t

pop_front

Usage:

using result = ctl::pop_front<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = L<T2, T3>`

if list provided is empty, then it will result in error

Variants:

  • pop_front

  • pop_front_t ⇒ to avoid ::type

pop_back

Usage:

using result = ctl::pop_back<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = L<T1, T2>`

Variants:

  • pop_back

  • pop_back_t ⇒ to avoid ::type

insert

Usage:

using result = ctl::insert_c<L<Ts...>, _index_, Us...>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `_index_ = 1`
    `Us... = U1, U2, U3`
then
    `result = L<T1, U1, U2, U3, T2, T3>`

if index should be less than size of the L<Ts…​>. otherwise it will result in compiler error

Variants:

  • insert_c

  • insert_c_t ⇒ to avoid ::type

  • insert ⇒ when index passed as type (::value is used to get the index value). ::type is needed to access the result type

  • insert_t ⇒ to avoid ::type

repeat

Usage:

using result = ctl::repeat_c<L<Ts...>, _count_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    _count_ = 2
then
    `result = L<T1, T2, T3, T1, T2, T3>`

if count == 0, then result = L<>

Variants:

  • repeat_c

  • repeat_c_t ⇒ to avoid ::type

  • repeat ⇒ when count passed as type (::value is used to get the count value). ::type is needed to access the result type

  • repeat_t ⇒ to avoid ::type

clear

Usage:

using result = ctl::repeat_c<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = L<>`

Variants:

  • clear

  • clear_t ⇒ to avoid ::type

erase

Usage:

using result = ctl::erase_c<L<Ts...>, _pos1_, _pos2_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    _pos1_ == 0
    _pos2_ == 1
then
    `result = L<T2, T3>`

if condition pos1 < L<Ts…​>pos2 fails, then results in compiler error.

Variants:

  • erase_c

  • erase_c_t ⇒ to avoid ::type

  • erase ⇒ when pos1 and pos2 are passed a types. ::type is needed to access the result type

  • erase_t ⇒ to avoid ::type

remove

Usage:

using result = ctl::remove_type<L<Ts...>, U>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `U = T2`
then
    `result = L<T1, T2>`

Variants:

  • remove_type

  • remove_type_t ⇒ to avoid ::type

  • remove_if ⇒ when U is a predicate. if P<T> results in true then type is removed. ::type is needed to access the result type

  • remove_if_t ⇒ to avoid ::type

  • remove_if_qmf

  • remove_if_qmf_t

filter

Usage:

using result = ctl::filter_if<P, L1, L2, ..., Ln>::type
if
    `L1 = L1<T1, T2, T3>,
    `L2 = L2<T4, T5, T6>`
    ...
    `Ln<Tn, Tn+1, Tn+2>`

    `P = P<T2, T5, ..., Tn+1> = true`
then
    `result = L<T2>`

Variants:

  • filter_if

  • filter_if_t ⇒ to avoid ::type

  • filter_if_qmf ⇒ when predicate is passed as quoted meta function. ::type is needed to access the result type

  • filter_if_qmf_t ⇒ to avoid ::type

copy_if

Usage:

using result = ctl::copy_if<L<Ts...>, P>::type
if
    `L<Ts...> = L<T1, T2, T3>`

    `P<T2> = true`
then
    `result = L<T2>`

Variants:

  • copy_if ⇒ alias to filter_if

  • copy_if_t ⇒ to avoid ::type

  • copy_if_qmf ⇒ alias to filter_if_qmf

  • copy_if_qmf_t ⇒ to avoid ::type

drop

Usage:

using result = ctl::drop_c<L<Ts...>, _count_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    _count_ = 2
then
    `result = L<T3>`

if count >= L<Ts…​> size, then result = L<>

Variants:

  • drop_c

  • drop_c_t ⇒ to avoid ::type

  • drop ⇒ when count is a type. ::type is needed to access the result type

  • drop_t ⇒ to avoid ::type

remove_duplicates

Usage:

using result = ctl::remove_duplicates<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T1, T2>`
    _count_ = 2
then
    `result = L<T1, T2>`

Variants:

  • remove_duplicates

  • remove_duplicates_t ⇒ to avoid ::type

unique

Usage:

using result = ctl::unique<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T1, T2>`
    _count_ = 2
then
    `result = L<T1, T2>`

Variants:

  • unique ⇒ alias to remove_duplicates

  • unique_t ⇒ to avoid ::type

unique_if

Usage:

using result = ctl::unique_if<L<Ts...>, P>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `P<T> = T2`
then
    `result = L<T1, T2>`

Variants:

  • unique_if ⇒ alias to remove_if

  • unique_if_t ⇒ to avoid ::type

  • unique_if_qmf ⇒ alias to remove_if_qmf

  • unique_if_qmf_t ⇒ to avoid ::type

transform

Usage:

using result = ctl::transform<F, L1, L2, ..., Ln>::type
if
    `L1 = L1<T1, T2, T3>
    `L2 = L2<T4, T5, T6> `
    ...
    `Ln<Tn, Tn+1, Tn+2>`
then
    `result = L<F<T1, T4, ..., Tn>, F<T2, T5, ..., Tn+1>, F<T3, T6, ..., Tn+2>>`.
    where, F is templated type.

Variants:

  • transform

  • transform_t ⇒ to avoid ::type

  • transform_qmf ⇒ when F is provided as quoted meta function. ::type is needed to access the result type

  • transform_qmf_t ⇒ to avoid ::type

  • transform_if ⇒ when predicate P is passed as 3rd template argument. result will have F<T> only when P<T> is true. ::type is needed to access the result type

  • transform_if_t ⇒ to avoid ::type

  • transform_if_qmf ⇒ when F and predicate provided as quoted meta function

  • transform_if_qmf_t ⇒ to avoid ::type

flatten

Usage:

using result = ctl::flatten<L1, L2=clear_t<L1>>::type
if
    `L1 = L1<T1, T2, std::tuple<T3>>
    `L2 = std::tuple<>`
then
    `result = L1<T1, T2, T3>

L2 is optional. If L2 is not provided, then L2 will be assumed as L1<>

Variants:

  • flatten

  • flatten_t ⇒ to avoid ::type

Accessors

Set of algorithms are used to retrieve the one or more types from the original list. In some case conditional retrieval is possible. These algorithms will result in compiler error if the provided list is empty.

General usage of the algorithm is:

using result = _algo name_<L<Ts...>, P>::type

where,

  • _ algo name _ ⇒ name of the accessor algorithms listed below

  • L<Ts…​> ⇒ list from which one or more type is retrieved

  • P ⇒ predicate/function which is applied on each type to access/retrieve.
    It is optional, not every algorithm needs this parameter

  • ::type ⇒ to access the type from the result.
    If algorithm name is postfixed with _t then there is no need of using ::type

Following are some of accessor algorithms (replaced with _ algo name _):

at

Usage:

using result = ctl::at_c<L<Ts...>, _pos_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    _pos_ == 2
then
    `result = T3`

If condition pos < size of L<Ts…​> then it will result in compiler error

Variants:

  • at_c

  • at_c_t ⇒ to avoid ::type

  • at ⇒ when pos is passed as type. ::type is needed to access the result type

  • at_t ⇒ to avoid ::type

first

Usage:

using result = ctl::first<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = T1`

If list provided is empty, then it will result in compiler error

Variants:

  • first ⇒ to get the first type from the list

  • first_t ⇒ to avoid ::type

front

Usage:

using result = ctl::front<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = T1`

If list provided is empty, then it will result in compiler error

Variants:

  • front ⇒ alias to first

  • front_t ⇒ to avoid ::type

last

Usage:

using result = ctl::last<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = T3`

If list provided is empty, then it will result in compiler error

Variants:

  • last ⇒ to get the last type from the list

  • last_t ⇒ to avoid ::type

back

Usage:

using result = ctl::back<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = T3`

If list provided is empty, then it will result in compiler error

Variants:

  • back ⇒ alias to last

  • back_t ⇒ to avoid ::type

head

Usage:

using result = ctl::head<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = L<T1, T2>`

If list provided is empty, then it will result in compiler error.
If there is only one entry in the list, then result = L<>

Variants:

  • head

  • head_t ⇒ to avoid ::type

tail

Usage:

using result = ctl::tail<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = L<T2, T3>`

If list provided is empty, then it will result in compiler error.
If there is only one entry in the list, then result = L<>

Variants:

  • tail

  • tail_t ⇒ to avoid ::type

take

Usage:

using result = ctl::take<L<Ts...>, _count_>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    _count_ = 2,
then
    `result = L<T1, T2>`

If count >= size of L<Ts…​> then result = L<Ts…​>

Variants:

  • take_c

  • take_c_t ⇒ to avoid ::type

  • take ⇒ when count is provided as type. ::type is needed to access the result type

  • take_t ⇒ to avoid ::type

Miscellaneous

Set of algorithms used for miscellaneous stuffs which are not listed above! like for ex, creating the integer sequence, getting the position of the type in a list, getting the size of the list, etc.

Following are some of algorithms:

size

Usage:

using result = ctl::size<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = std::integral_constant<uint32_t, 3>`

Variants:

  • size

  • size_t ⇒ to avoid ::type

  • size_v ⇒ to avoid ::value

count

Usage:

using result = ctl::count<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = std::integral_constant<uint32_t, 3>`

Variants:

  • count ⇒ alias to size

  • count_t ⇒ to avoid ::type

  • count_v ⇒ to avoid ::value

  • count_if ⇒ when predicate P is passed as second template argument. type will be counted only if P<T> is true. ::type is needed to access the result type

  • count_if_t ⇒ to avoid ::type

  • count_if_v ⇒ to avoid ::value

  • count_if_qmf ⇒ when predicate is passed as quoted meta function

  • count_if_qmf_t ⇒ to avoid ::type

  • count_if_qmf_v ⇒ to avoid ::value

empty

Usage:

using result = ctl::empty<L<Ts...>>::type
if
    `L<Ts...> = L<T1, T2, T3>`
then
    `result = std::false_type`

If L<Ts…​> = L<> then result = std::true_type

Variants:

  • empty

  • empty_t ⇒ to avoid ::type

  • empty_v ⇒ to avoid ::value

contains

Usage:

using result = ctl::contains<L<Ts...>, U>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `U == T2`
then
    `result = std::true_type`

If U == T4 then result = std::false_type

Variants:

  • contains

  • contains_t ⇒ to avoid ::type

  • contains_v ⇒ to avoid ::value

find

Usage:

using result = ctl::find<L<Ts...>, U>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `U == T2`
then
    `result = std::integral_constant<uint32_t, 1>`.

If U is not found in list, then result is size of the list

Variants:

  • find

  • find_t ⇒ to avoid ::type

  • find_v ⇒ to avoid ::value

  • find_if ⇒ when U is a predicate. result will have the first position for which P<T> will result in true. ::type is needed to access the result type

  • find_if_t ⇒ to avoid ::type

  • find_if_v ⇒ to avoid ::value

  • find_if_qmf ⇒ when predicate is passed as quoted meta function. ::type is needed to access the result type

  • find_if_qmf_t ⇒ to avoid ::type

  • find_if_qmf_v ⇒ to avoid ::value

all_of

Usage:

using result = ctl::all_of<L<Ts...>, P>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `P<T> == true` for all T1, T2, T3 types
then
    `result = std::true_type`,
    `result = std::false_type`, if P<T> == false for any one of the types

Variants:

  • all_of

  • all_of_t ⇒ to avoid ::type

  • all_of_v ⇒ to avoid ::value

  • all_of_qmf ⇒ when predicate is passed as quoted meta function. ::type is needed to access the result type

  • all_of_qmf_t ⇒ to avoid ::type

  • all_of_qmf_v ⇒ to avoid ::value

any_of

Usage:

using result = ctl::any_of<L<Ts...>, P>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `P<T> == true` for any T1, T2, T3 types
then
    `result = std::true_type`,
    `result = std::false_type`, if P<T> == false for all types

Variants:

  • any_of

  • any_of_t ⇒ to avoid ::type

  • any_of_v ⇒ to avoid ::value

  • any_of_qmf ⇒ when predicate is passed as quoted meta function. ::type is needed to access the result type

  • any_of_qmf_t ⇒ to avoid ::type

  • any_of_qmf_v ⇒ to avoid ::value

none_of

Usage:

using result = ctl::none_of<L<Ts...>, P>::type
if
    `L<Ts...> = L<T1, T2, T3>`
    `P<T> == false` for all T1, T2, T3 types
then
    `result = std::true_type`,
    `result = std::false_type`, if P<T> for any one of the types

Variants:

  • none_of

  • none_of_t ⇒ to avoid ::type

  • none_of_v ⇒ to avoid ::value

  • none_of_qmf ⇒ when predicate is passed as quoted meta function. ::type is needed to access the result type

  • none_of_qmf_t ⇒ to avoid ::type

  • none_of_qmf_v ⇒ to avoid ::value

from integer sequence

Usage:

using result = ctl::from_integer_sequence<sequence, RT>::type
if
    `sequence = std::integer_sequence<unsigned int, 9, 2, 5>`
    `RT == ctl::list`
then
    `result = ctl::list<std::integral_constant<unsigned int, 9>, std::integral_constant<unsigned int, 2>, std::integral_constant<unsigned int, 5> >`

RT default type is std::tuple.

Variants:

  • from_integer_sequence

  • from_integer_sequence_t ⇒ to avoid ::type

iota

Usage:

using result = ctl::iota_c<_count_, DT, RT>::type
if
    _count_ = 3,
    `DT = uint32_t`
    `RT == ctl::list`
then
    `result = ctl::list<std::integral_constant<uint32_t, 0>, std::integral_constant<uint32_t, 1>, std::integral_constant<uint32_t, 2> >`

DT default type is uint32_t.
RT default type is std::tuple.

  • iota_c

  • iota_c_t ⇒ to avoid ::type

  • iota ⇒ when count is provided as type. ::type is needed to access the result type

  • iota_t ⇒ to avoid ::type

is_similar

Usage:

using result = ctl::is_similar<T1, T2>::type
if
    T1 = std::tuple<Ts...>,
    T2 = std::tuple<Us...>
then
    `result = std::integral_constant<bool, true>

if T1 or T2 are not similar list, then result will be false type

  • is_similar

  • is_similar_t ⇒ to avoid ::type

  • is_similar_v ⇒ to avoid ::value

Utility

Following struct(s)/algorithm(s) can be applied on the types. To use algorithms make sure to add #include <utils.hpp> in source file.

quote

This helps to wrap template type inside a structure called quote.
Template type can be accessed with the help of nested type fn.

template <template <typename...> typename F>
struct quote {
    template <typename... Ts>
    using fn = F<Ts...>;
};

invert

This helps to invert the provided type/value.

template <bool C>
struct invert_c {
  ...
};

variants of invert are:

  • invert_c

  • invert_c_t ⇒ to avoid ::type

  • invert_c_v ⇒ to avoid ::value

  • invert ⇒ to pass typename as template parameter.
    boolean value is accessed with the help of C::value

  • invert_t ⇒ to avoid ::type

  • invert_v ⇒ to avoid ::value

valid

This helps to validate if the provided template type is valid or not.

template <template <typename...> typename F, typename... Ts>
struct valid {
  ...
};

It results in std::true_type if F<Ts…​>::type is valid. std::false_type otherwise.

variants of valid are:

  • valid

  • valid_t ⇒ to avoid using ::type

  • valid_v ⇒ to avoid using ::value

  • valid_qmf ⇒ to pass template function as a quoted meta function

  • valid_qmf_t ⇒ to avoid using ::type

  • valid_qmf_v ⇒ to avoid using ::value

select

This is equivalent of ternary operator but for types.

template <bool C, typename T, typename F>
struct select_c {
  ...
};

If condition C is true, select_c<>::type will be alias to T, to F otherwise.

variants of select are:

  • select_c ⇒ when condition is true/false value. ::type required to retrieve the type

  • select_c_t ⇒ to avoid ::type

  • select ⇒ when condition is a type.
    boolean value is accessed with the help of C::value

  • select_t ⇒ to avoid ::type

Following variants of select is used to get the false type as templated function.
i.e. if condition results in false then selected type is F<Ts…​>.

template <bool C, typename T, template <typename...> typename F, typename... Ts>
using select_f_c_t {
  ...
};
  • select_f_c ⇒ when condition is true/false value. ::type required to retrieve the type

  • select_f_c_t ⇒ to avoid ::type

  • select_f ⇒ when condition is a type. boolean value is accessed with the help of C::value

  • select_f_t ⇒ to avoid ::type

  • select_qmf_c ⇒ when false type is captured with quoted meta function, and condition is true/false value

  • select_qmf_c_t ⇒ to avoid ::type

  • select_qmf ⇒ when false type is captured with quoted meta function, and condition is a type

  • select_qmf_t ⇒ to avoid ::type

is_function

This will check if the provided type is a function or not.

template <typename T>
struct is_function {
  ...
};

If the provided type is not a reference and adding const to type will not result in the const, then it is considered as function.

variants of is_function are:

  • is_function_t ⇒ to avoid using ::type

  • is_function_v ⇒ to avoid using ::value

is_invocable

This will check if the provided type is a function OR a class which implements operator()

template <typename T>
struct is_invocable {
  ...
};

It makes use of the CPP member detection idiom technique.

If the provided T is a function, then it will result in std::true_type
If the provided T is a class, if it implements operator() then it will result in std::true_type
otherwise it will result in std::false_type

variants of is_invocable are:

  • is_invocable_t ⇒ to avoid using ::type

  • is_invocable_v ⇒ to avoid using ::value