Documentation Overview¶
Welcome to the documentation of m3ta.
Getting Started¶
Overview¶
m3ta is an header-only library regrouping utilities for template metaprogramming.
It relies on features implemented in C++11 and requires as such C++11 or above.
Check out the Examples section to see some use cases.
Note
The library has been tested only against Clang 3.5.0 but should work on any C++11 compliant compiler.
Examples¶
Function Call at Compile Time¶
Let’s consider the case of 2D texture tiles to be used in the context of tile-based texture mapping within graphic renderers such as OpenGL. Such tiles must be square and it is often recommended for hardware optimisations and/or limitations to set their size to a power of two.
template<int T_size>
class TextureTile2D
{};
Defining the size as a template parameter force the user to provide it at compile time, allowing some possible further optimisations.
As it stands with this class definition, a 2D texture tile could be initialized by passing any value—power of two, or not.
TextureTile2D<256> powerOfTwoTexture;
TextureTile2D<123> nonPowerOfTwoTexture;
To avoid the risk of passing non power of two values by mistake, one could decide to use a power function such as the stardard std::pow().
TextureTile2D<std::pow(2, 8)> powerOfTwoTexture;
Expect that this won’t compile because the template parameter T_size needs to be set at compile time while the std::pow() function can only be ran at runtime. That’s where the m3ta::power() function comes into play.
TextureTile2D<m3ta::power(2, 8)> powerOfTwoTexture;
This works because the m3ta::power() function—like all the other functions from this library—is defined with the constexpr qualifier introduced in C++11, allowing it to run either at runtime or at compile time, depending on the context. The context here being a template parameter, the function runs at compile time.
Tag Dispatching¶
Building on the previous example, let’s assume that TextureTile2D has a method that does something where the computations involved could be highly optimized if the size passed as argument was a power of two less than 1024.
constexpr bool isPowerOfTwo(int value) { ... }
template<int T_size>
class TextureTile2D
{
public:
void doSomething()
{
if (isPowerOfTwo(T_size) && T_size < 1024) {
// Run optimized code.
}
else {
// Run unoptimized code.
}
}
};
This runs fine but the conditional check is done here at runtime even though the value T_size is known at compile time and that the function isPowerOfTwo can also run at compile time. If the check was expensive, it could be worthwhile to compute it once for all at compile time.
constexpr bool isPowerOfTwo(int value) { ... }
template<int T_size>
class TextureTile2D
{
public:
void
doSomething()
{
doSomething_impl(m3ta::All<bool, isPowerOfTwo(T_size), T_size < 1024>());
}
private:
void
doSomething_impl(std::true_type)
{
// Run optimized code.
}
void
doSomething_impl(std::false_type)
{
// Run unoptimized code.
}
};
Here the trait m3ta::All inherits from std::true_type (an alias of std::integral_type<bool, true>) if all the conditions passed to m3ta::All evaluate to true, and from std::false_type otherwise.
This is called the tag dispatching technique—it allows to pick either one of the implementations at compile time.
Overload Resolution Using SFINAE¶
template<typename T1, typename T2, typename = void>
struct AreComparableForEquality
{
static constexpr bool value = false;
};
template<typename T1, typename T2>
struct AreComparableForEquality<
T1,
T2,
typename std::enable_if<
true,
m3ta::PassT<void, decltype(std::declval<T1>() == std::declval<T2>())>
>::type
>
{
static constexpr bool value = true;
};
This AreComparableForEquality trait defined here allows to check if two types can be compared for equality using the operator ==. For example AreComparableForEquality<int, float>::value returns true while AreComparableForEquality<std::string, float>::value returns false.
This works by using the SFINAE technique over template parameters—if the code std::declval<T1>() == std::declval<T2>() is not a valid expression (no equality operator is defined between he types T1 and T2), then the default overload holding the value false is picked, otherwise the second one is chosen at one condition: the specialization of the third parameter must return void as per the default template parameter from the first overload.
m3ta::PassT is a used here to conveniently test the SFINAE expression while always returning the required type.
Static Assert¶
Let’s assume a Divide struct that would operate divisions between two integers at compile time. To disallow divisions by 0, a possibility could be to define a template specialization for the divisor value that would trigger an informative error message at compile time using static_assert.
template<int T_dividend, int T_divisor>
struct Divide
{
static constexpr int value = T_dividend / T_divisor;
};
template<int T_dividend>
struct Divide<T_dividend, 0>
{
static_assert(false, "Division by 0 not allowed.");
};
This code won’t work because the static_assert will always be evaluated to false during the compilation—and hence will trigger a compilation error—even when no code path would lead to instantiate the version with that template specialization.
To get it to work, the evaluation of the static_assert needs to be slightly deferred by making it dependent on a type—any type really, including empty parameter packs—with the help of the m3ta::dependenBool() function.
template<int T_dividend, int T_divisor, typename ... T_Dummies>
struct Base
{
static constexpr int value = T_dividend / T_divisor;
};
template<int T_dividend, typename ... T_Dummies>
struct Base<T_dividend, 0, T_Dummies ...>
{
static_assert(
m3ta::dependentBool<T_Dummies ...>(false),
"Division by 0 not allowed."
);
};
template<int T_dividend, int T_divisor>
struct Divide
: public Base<T_dividend, T_divisor>
{};
The Nested Initializers Trick for Multidimensional Arrays¶
The built-in C/C++ arrays come with a convenient syntax to initialize them: the curly braces.
int array[2][3] = {
0, 1, 2,
3, 4, 5
};
The definition of array produces a multidimensional array that represents 2 arrays of 3 elements each.
The same array could have been written with an extra pair of brace for each inner dimension.
int array[2][3] = {
{0, 1, 2},
{3, 4, 5}
};
With the introduction of the initializer lists in C++11, this syntax is now usable within custom types. Reproducing the first syntax requires a constructor to accept a single std::initializer_list argument, while the nested braces syntax requires a parameter to be defined as nested initializer lists.
template<typename T, std::size_t ... T_dimensions>
class MultidimensionalArray
{
protected:
using NestedInitializerLists =
m3ta::NestedInitializerListsT<T, sizeof ... (T_dimensions)>;
public:
static constexpr std::size_t
size()
{
return m3ta::product(T_dimensions ...);
}
MultidimensionalArray(NestedInitializerLists lists)
{ ... }
private:
std::array<T, size()> _data;
};
The m3ta::NestedInitializerLists traits allows to quickly define a new type with a specified number of std::initializer_list nested within each other, while the m3ta::product() function returns the total size of the multidimensional array.
From there, iterating through each element is not as simple as iterating over a linear container. Indeed, iterating through the std::initializer_lists at the top level with the function begin() returns pointers to the deeper levels. As such, the elements initialized with the nested braces syntax can only be iterated through a recursive approach.
template<typename T, std::size_t ... T_shape>
struct NestedInitializerListsProcessor;
template<typename T, std::size_t T_first, std::size_t ... T_others>
struct NestedInitializerListsProcessor<T, T_first, T_others ...>
{
using NestedInitializerLists =
m3ta::NestedInitializerListsT<T, 1 + sizeof ... (T_others)>;
template<typename T_Function>
static void
process(NestedInitializerLists lists, T_Function function)
{
if (lists.size() > T_first) {
throw std::invalid_argument(
"Elements in excess within the initilizer list."
);
}
for (auto nested : lists) {
NestedInitializerListsProcessor<T, T_others ...>::
process(nested, function);
}
if (T_first != lists.size()) {
std::size_t count =
m3ta::product(T_others ...) * (T_first - lists.size());
for (; count > 0; --count) {
function(static_cast<T>(0));
}
}
}
};
template<typename T, std::size_t T_last>
struct NestedInitializerListsProcessor<T, T_last>
{
using InitializerList = m3ta::NestedInitializerListsT<T, 1>;
template<typename T_Function>
static void
process(InitializerList list, T_Function function)
{
if (list.size() > T_last) {
throw std::invalid_argument(
"Elements in excess within the initilizer list."
);
}
std::for_each(list.begin(), list.end(), function);
if (T_last != list.size()) {
std::size_t count = T_last - list.size();
for (; count > 0; --count) {
function(static_cast<T>(0));
}
}
}
};
The NestedInitializerListsProcessor helper can iterate through nested std::initializer_lists while allowing a custom function to be applied on each element.
With this in hands, it is now possible to fully implement the constructor for the nested braces syntax.
template<typename T, std::size_t ... T_dimensions>
class MultidimensionalArray
{
protected:
using NestedInitializerLists =
m3ta::NestedInitializerListsT<T, sizeof ... (T_dimensions)>;
public:
static constexpr std::size_t
size()
{
return m3ta::product(T_dimensions ...);
}
MultidimensionalArray(NestedInitializerLists lists)
{
auto iterator = _data.begin();
NestedInitializerListsProcessor<T, T_dimensions ...>::
process(
lists,
[&iterator](T value) { *(iterator++) = value; }
);
}
private:
std::array<T, size()> _data;
};
What’s Available?¶
Reference¶
#include <m3ta/m3ta>
Constants¶
Regroups the utilities that are outputting constant values.
They are defined both as constexpr functions and as conventional traits inheriting from std::integral_constant.
All¶
#include <m3ta/all>
Checks if all the values evaluate to true.
Functions¶
- m3ta::all
template<typename ... T_Values> constexpr bool all(T_Values ... values) noexcept
Template Parameters: - T_Values (automatically deduced) — Types of the values to check.
Function Parameters: - values – Variable number of values to check. Those can be of heterogeneous types.
Returns
Whether all the values evaluate to true.
Traits¶
- m3ta::All
template<typename T, T ... T_values> struct All
Template Parameters: - T – Type of the values to check.
- T_values – Variable number of values to check.
Member Types
- type
The type std::integral_constant<bool, value> where value is the result of the function m3ta::all().
- value_type
The type bool.
Member Constants
- static constexpr bool value
Whether all the values evaluate to true.
Aliases¶
- m3ta::AllT
template<typename T, T ... T_values> using AllT = typename All<T, T_values ...>::type;
Usage Examples¶
bool value1 = m3ta::all(true, true); // true
bool value2 = m3ta::all(false, false); // false
bool value3 = m3ta::all(true, false); // false
bool value4 = m3ta::all(true, 1, 2L, 4.0f, 9.0, 85.0L); // true
using Type1 = m3ta::AllT<bool, true, true>; // std::integral_constant<bool, true>
using Type2 = m3ta::AllT<bool, false, false>; // std::integral_constant<bool, false>
using Type3 = m3ta::AllT<bool, true, false>; // std::integral_constant<bool, false>
using Type4 = m3ta::AllT<bool, 1, 2, 4, 9, 85>; // std::integral_constant<bool, true>
Any¶
#include <m3ta/any>
Checks if any of the values evaluate to true.
Functions¶
- m3ta::any
template<typename ... T_Values> constexpr bool any(T_Values ... values) noexcept
Template Parameters: - T_Values (automatically deduced) — Types of the values to check.
Function Parameters: - values – Variable number of values to check. Those can be of heterogeneous types.
Returns
Whether any of the values evaluate to true.
Traits¶
- m3ta::Any
template<typename T, T ... T_values> struct Any
Template Parameters: - T – Type of the values to check.
- T_values – Variable number of values to check.
Member Types
- type
The type std::integral_constant<bool, value> where value is the result of the function m3ta::any().
- value_type
The type bool.
Member Constants
- static constexpr bool value
Whether any of the values evaluate to true.
Aliases¶
- m3ta::AnyT
template<typename T, T ... T_values> using AnyT = typename Any<T, T_values ...>::type;
Usage Examples¶
bool value1 = m3ta::any(true, true); // true
bool value2 = m3ta::any(false, false); // false
bool value3 = m3ta::any(true, false); // true
bool value4 = m3ta::any(true, 1, 2L, 4.0f, 9.0, 85.0L); // true
using Type1 = m3ta::AnyT<bool, true, true>; // std::integral_constant<bool, true>
using Type2 = m3ta::AnyT<bool, false, false>; // std::integral_constant<bool, false>
using Type3 = m3ta::AnyT<bool, true, false>; // std::integral_constant<bool, true>
using Type4 = m3ta::AnyT<bool, 1, 2, 4, 9, 85>; // std::integral_constant<bool, true>
Ending Occurrences¶
#include <m3ta/endingoccurrences>
Counts the number of occurrences of a value at the end of a sequence of elements.
Functions¶
- m3ta::endingOccurrences
template<typename T_Search, typename ... T_Values> constexpr std::size_t endingOccurrences(T_Search search, T_Values ... values) noexcept
Template Parameters: - T_Search (automatically deduced) — Type of the value to search for.
- T_Values (automatically deduced) — Types of the values to search in.
Function Parameters: - search – Value to search for.
- values – Variable number of values to search in. Those can be of heterogeneous types.
Note
Values of heterogeneous types can be passed to the values parameter only if they all can be compared for equality (==) against the value to be searched for.
Returns
The number of occurrences of the search value at the end of the values elements.
Traits¶
- m3ta::EndingOccurrences
template<typename T, T T_search, T ... T_values> struct EndingOccurrences
Template Parameters: - T – Type of the values to check.
- T_Search – Value to search for.
- T_Values – Variable number of values to search in.
Member Types
- type
The type std::integral_constant<std::size_t, value> where value is the result of the function m3ta::endingOccurrences().
- value_type
The type std::size_t.
Member Constants
- static constexpr std::size_t value
The number of occurrences of the search value at the end of the T_values elements.
Aliases¶
- m3ta::EndingOccurrencesT
template<typename T, T T_search, T ... T_values> using EndingOccurrencesT = typename EndingOccurrences<T, T_search, T_values ...>::type;
Usage Examples¶
std::size_t value1 = m3ta::endingOccurrences(4, 1, 2, 4, 4, 4); // 3
std::size_t value2 = m3ta::endingOccurrences(4, 1, 4, 2, 4, 4); // 2
std::size_t value3 = m3ta::endingOccurrences(4.0f, std::complex<float>(4, 0)); // 1
using Type1 = m3ta::EndingOccurrencesT<int, 4, 1, 2, 4, 4, 4>; // std::integral_constant<std::size_t, 1>
using Type2 = m3ta::EndingOccurrencesT<int, 4, 1, 4, 2, 4, 4>; // std::integral_constant<std::size_t, 2>
Is Complex?¶
#include <m3ta/iscomplex>
Checks if a type is the same as std::complex.
Note
Following the behavior of the type traits from the C++ standard library, the check will return false is a std::complex type is passed as a reference.
Functions¶
- m3ta::isComplex
template<typename T> constexpr bool isComplex() noexcept
Template Parameters: - T — Type to check.
Returns
Whether the type is the same as std::complex.
Traits¶
- m3ta::IsComplex
template<typename T> struct IsComplex
Template Parameters: - T – Type to check.
Member Types
- type
The type std::integral_constant<bool, value> where value is the result of the function m3ta::isComplex().
- value_type
The type bool.
Member Constants
- static constexpr bool value
Whether the type is the same as std::complex.
Aliases¶
- m3ta::IsComplexT
template<typename T> using IsComplexT = typename IsComplex<T>::type;
Usage Examples¶
bool value1 = m3ta::isComplex<float>() // false
bool value2 = m3ta::isComplex<std::complex<float>>() // true
bool value3 = m3ta::isComplex<std::complex<float> &>() // false
using Type1 = m3ta::IsComplexT<float>; // std::integral_constant<bool, false>
using Type2 = m3ta::IsComplexT<std::complex<float>>; // std::integral_constant<bool, true>
using Type3 = m3ta::IsComplexT<std::complex<float> &>; // std::integral_constant<bool, false>
Is Operator Callable?¶
#include <m3ta/isoperatorcallable>
Checks if an operator can be called on given types.
Enumerators¶
- m3ta::UnaryOperator
enum class UnaryOperator { plus, minus, postfixIncrement, postfixDecrement, prefixIncrement, prefixDecrement, logicalNot, bitwiseNot };
- plus
Plus operator +a.
- minus
Minus operator -a.
- posfixIncrement
Postfix increment operator a++.
- postfixDecrement
Postfix decrement operator a--.
- prefixIncrement
Prefix increment operator ++a.
- prefixDecrement
Prefix decrement operator --a.
- logicalNot
Logical NOT operator !a.
- bitwiseNot
Bitwise NOT operator ~a.
- m3ta::BinaryOperator
enum class BinaryOperator { assignment, addition, subtraction, multiplication, division, modulo, equalTo, notEqualTo, greaterThan, lessThan, greaterThanOrEqualTo, lessThanOrEqualTo, logicalAnd, logicalOr, bitwiseAnd, bitwiseOr, bitwiseXor, bitwiseLeftShift, bitwiseRightShift, additionAssignment, subtractionAssignment, multiplicationAssignment, divisionAssignment, moduloAssignment, bitwiseAndAssignment, bitwiseOrAssignment, bitwiseXorAssignment, bitwiseLeftShiftAssignment, bitwiseRightShiftAssignment };
- assignment
Assignment operator a = b.
- addition
Addition operator a + b.
- subtraction
Subtraction operator a - b.
- multiplication
Multiplication operator a * b.
- division
Division operator a / b.
- modulo
Modulo operator a % b.
- equalTo
Equal to operator a == b.
- notEqualTo
Not equal to operator a != b.
- greaterThan
Greater than operator a > b.
- lessThan
Less than operator a < b.
- greaterThanOrEqualTo
Greater than or equal to operator a >= b.
- lessThanOrEqualTo
Less than or equal to operator a <= b.
- logicalAnd
Logical AND operator a && b.
- logicalOr
Logical OR operator a || b.
- bitwiseAnd
Bitwise AND operator a & b.
- bitwiseOr
Bitwise OR operator a | b.
- bitwiseXOr
Bitwise XOR operator a ^ b.
- bitwiseLeftShift
Bitwise left shift operator a << b.
- bitwiseRightShift
Bitwise right shift operator a >> b.
- additionAssignment
Addition assignment operator a += b.
- subtractionAssignment
Subtraction assignment operator a -= b.
- multiplicationAssignment
Multiplication assignment operator a *= b.
- divisionAssignment
Division assignment operator a /= b.
- moduloAssignment
Modulo assignment operator a %= b.
- bitwiseAndAssignment
Bitwise AND assignment operator a &= b.
- bitwiseOrAssignment
Bitwise OR assignment operator a |= b.
- bitwiseXOrAssignment
Bitwise XOR assignment operator a ^= b.
- bitwiseLeftShiftAssignment
Bitwise left shift assignment operator a <<= b.
- bitwiseRightShiftAssignment
Bitwise right shift assignment operator a >>= b.
Functions¶
- m3ta::isOperatorCallable
template<UnaryOperator T_operator, typename T> constexpr bool isOperatorCallable() noexcept template<BinaryOperator T_operator, typename T, typename T_Other> constexpr bool isOperatorCallable() noexcept
Template Parameters: - T_operator — Operator to check for.
- T — Type of the first operand.
- T_Other — Type of the second operand. For binary operators only.
Returns
Whether the operator can be called on the operand(s).
Traits¶
- m3ta::IsOperatorCallable
template<typename T_Operator, T_Operator T_operator, typename ... T> struct IsOperatorCallable;
Template Parameters: - T_Operator – Type of the operator to check for.
- T_operator – Operator to check for.
- T - Type of the operand(s). Only one operand is expected when checking against unary operators, and two for the binary operators.
Member Types
- type
The type std::integral_constant<bool, value> where value is the result of the function m3ta::isOperatorCallable().
- value_type
The type bool.
Member Constants
- static constexpr bool value
Whether the operator can be called on the operand(s).
Aliases¶
- m3ta::IsOperatorCallableT
template<typename T_Operator, T_Operator T_operator, typename ... T> using IsOperatorCallableT = typename IsOperatorCallable<T_Operator, T_operator, T ...>::type;
Usage Examples¶
bool value1 = m3ta::isOperatorCallable<
m3ta::UnaryOperator::logicalNot,
int
>(); // true
bool value2 = m3ta::isOperatorCallable<
m3ta::BinaryOperator::addition,
int,
float
>(); // true
bool value3 = m3ta::isOperatorCallable<
m3ta::BinaryOperator::multiplication,
int,
std::complex<float>
>(); // false
using Type1 = m3ta::IsOperatorCallableT<
m3ta::UnaryOperator::logicalNot,
int
>; // std::integral_constant<bool, true>
using Type2 = m3ta::IsOperatorCallableT<
m3ta::BinaryOperator::addition,
int,
float
>; // std::integral_constant<bool, true>
using Type3 = m3ta::IsOperatorCallableT<
m3ta::BinaryOperator::multiplication,
int,
std::complex<float>
>; // std::integral_constant<bool, false>
Maximum¶
#include <m3ta/maximum>
Returns the greater of two values.
See Also
Functions¶
- m3ta::maximum
template<typename T> constexpr T maximum(T value1, T value2) noexcept
Template Parameters: - T (automatically deduced) — Type of the values to compare.
Function Parameters: - value1 – First value to compare.
- value2 – Second value to compare.
Returns
The greater of the two values.
Traits¶
- m3ta::Maximum
template<typename T, T T_value1, T T_value2> struct Maximum
Template Parameters: - T – Type of the values to check.
- T_value1 – First value to compare.
- T_value2 – Second value to compare.
Member Types
- type
The type std::integral_constant<T, value> where value is the result of the function m3ta::maximum().
- value_type
The type T.
Member Constants
- static constexpr T value
The greater of the two values.
Aliases¶
- m3ta::MaximumT
template<typename T, T T_value1, T T_value2> using MaximumT = typename Maximum<T, T_value1, T_value2>::type;
Usage Examples¶
auto value = m3ta::maximum(1, 2); // 2
using Type = m3ta::MaximumT<int, 1, 2>; // std::integral_constant<int, 2>
Minimum¶
#include <m3ta/minimum>
Returns the greater of two values.
See Also
Functions¶
- m3ta::minimum
template<typename T> constexpr T minimum(T value1, T value2) noexcept
Template Parameters: - T (automatically deduced) — Type of the values to compare.
Function Parameters: - value1 – First value to compare.
- value2 – Second value to compare.
Returns
The greater of the two values.
Traits¶
- m3ta::Minimum
template<typename T, T T_value1, T T_value2> struct Minimum
Template Parameters: - T – Type of the values to check.
- T_value1 – First value to compare.
- T_value2 – Second value to compare.
Member Types
- type
The type std::integral_constant<T, value> where value is the result of the function m3ta::minimum().
- value_type
The type T.
Member Constants
- static constexpr T value
The greater of the two values.
Aliases¶
- m3ta::MinimumT
template<typename T, T T_value1, T T_value2> using MinimumT = typename Minimum<T, T_value1, T_value2>::type;
Usage Examples¶
auto value = m3ta::minimum(1, 2); // 1
using Type = m3ta::MinimumT<int, 1, 2>; // std::integral_constant<int, 1>
None¶
#include <m3ta/none>
Checks if none of the values evaluate to true.
Functions¶
- m3ta::none
template<typename ... T_Values> constexpr bool none(T_Values ... values) noexcept
Template Parameters: - T_Values (automatically deduced) — Types of the values to check.
Function Parameters: - values – Variable number of values to check. Those can be of heterogeneous types.
Returns
Whether none of the values evaluate to true.
Traits¶
- m3ta::None
template<typename T, T ... T_values> struct None
Template Parameters: - T – Type of the values to check.
- T_values – Variable number of values to check.
Member Types
- type
The type std::integral_constant<bool, value> where value is the result of the function m3ta::none().
- value_type
The type bool.
Member Constants
- static constexpr bool value
Whether none of the values evaluate to true.
Aliases¶
- m3ta::NoneT
template<typename T, T ... T_values> using NoneT = typename None<T, T_values ...>::type;
Usage Examples¶
bool value1 = m3ta::none(true, true); // false
bool value2 = m3ta::none(false, false); // true
bool value3 = m3ta::none(true, false); // false
bool value4 = m3ta::none(true, 1, 2L, 4.0f, 9.0, 85.0L); // false
using Type1 = m3ta::NoneT<bool, true, true>; // std::integral_constant<bool, false>
using Type2 = m3ta::NoneT<bool, false, false>; // std::integral_constant<bool, true>
using Type3 = m3ta::NoneT<bool, true, false>; // std::integral_constant<bool, false>
using Type4 = m3ta::NoneT<bool, 1, 2, 4, 9, 85>; // std::integral_constant<bool, false>
Power¶
#include <m3ta/power>
Functions¶
- m3ta::power
template<typename T_Base, typename T_Exponent> constexpr MultiplicationResultT<T_Base, T_Base> power(T_Base base, T_Exponent exponent) noexcept
Template Parameters: - T_Base (automatically deduced) — Type of the base value.
- T_Exponent (automatically deduced) — Type of the exponent value.
Function Parameters: - base – Base value.
- exponent – Exponent value.
Returns
The number base raised to the power exponent.
Traits¶
- m3ta::Power
template<typename T, T T_base, T T_exponent> struct Power
Template Parameters: - T – Type of the values.
- T_base – Base value.
- T_exponent – Exponent value.
Member Types
- type
The type std::integral_constant<T, value> where value is the result of the function m3ta::power().
- value_type
The type T.
Member Constants
- static constexpr T value
The number T_base raised to the power T_exponent.
Aliases¶
- m3ta::PowerT
template<typename T, T T_base, T T_exponent> using PowerT = typename Power<T, T_base, T_exponent>::type;
Usage Examples¶
auto value1 = m3ta::power(4, 3); // 64
auto value2 = m3ta::power(1.0f, -1); // 0.5
auto value3 = m3ta::power(std::complex<float>(1, 1), 2); // std::complex<float>(0, 2)
using Type = m3ta::PowerT<int, 4, 3>; // std::integral_constant<int, 64>
Product¶
#include <m3ta/product>
Computes the product of a sequence of elements.
The computation follows a left-to-right associativity, meaning that a * b * c is evaluated as (a * b) * c.
Functions¶
- m3ta::product
template<typename T_First, typename ... T_Others> constexpr m3ta::MultiplicationResultT<T_First, T_Others ...> product(T_First first, T_Others ... others) noexcept
The arguments passed do not have to be of numeric type—custom types such as matrices and vectors can be passed as soon as they define arithmetic multiplications with the values preceding and/or following them.
Template Parameters: - T_First (automatically deduced) — Type of the first value to multiply.
- T_Others (automatically deduced) — Types of the other values to mutiply.
Function Parameters: - first – First value to multiply.
- others – Other values to multiply.
Returns
The product of the values.
Traits¶
- m3ta::Product
template<typename T, T T_first, T ... T_others> struct Product
Template Parameters: - T – Type of the values.
- T_first – First value to multiply.
- T_others – Other values to multiply.
Member Types
- type
The type std::integral_constant<T, value> where value is the result of the function m3ta::product().
- value_type
The type T.
Member Constants
- static constexpr T value
The product of the values.
Aliases¶
- m3ta::ProductT
template<typename T, T T_first, T ... T_others> using ProductT = typename Product<T, T_first, T_others ...>::type;
- m3ta::IndexProduct
template<std::size_t T_first, std::size_t ... T_others> using IndexProduct = Product<std::size_t, T_first, T_others ...>;
- m3ta::IndexProductT
template<std::size_t T_first, std::size_t ... T_others> using IndexProductT = typename IndexProduct<T_first, T_others ...>::type;
Usage Examples¶
auto value1 = m3ta::product(1, 2, 4); // 8
auto value2 = m3ta::product(4.9, 85); // 416.5
auto value3 = m3ta::product(std::complex<float>(2, 2), 4); // std::complex<float>(8, 8)
using Type = m3ta::ProductT<int, 1, 2, 4>; // std::integral_constant<int, 8>
Types¶
Traits defining a type member holding the resulting type of an operation.
An alias ending with the prefix T that refers to the type member is also available as a convenience.
Arithmetic Operation Result¶
#include <m3ta/arithmeticoperationresult>
Deduces the resulting type of an arithmetic operation between the given type elements.
The deduction follows a left-to-right associativity, meaning that a + b + c is evaluated as (a + b) + c.
Enumerators¶
- m3ta::ArithmeticOperator
enum class ArithmeticOperator { addition, subtraction, multiplication, division };
- addition
Addition operator +.
- subtraction
Subtraction operator -.
- multiplication
Multiplication operator *.
- division
Division operator /.
Traits¶
- m3ta::ArithmeticOperationResult
template<ArithmeticOperator T_operator, typename ... T_Values> struct ArithmeticOperationResult
Template Parameters: - T_operator – Operator to use for the check.
- T_Values – Variable number of types to check.
Member Types
- type
The resulting type of the arithmetic operation between the given type elements.
Aliases¶
- m3ta::ArithmeticOperationResultT
template<ArithmeticOperator T_operator, typename ... T_Values> using ArithmeticOperationResultT = typename ArithmeticOperationResult<T_operator, T_Values ...>::type;
- m3ta::AdditionResult
template<typename ... T_Values> using AdditionResult = ArithmeticOperationResult<ArithmeticOperator::addition, T_Values ...>;
- m3ta::AdditionResultT
template<typename ... T_Values> using AdditionResultT = typename AdditionResult<T_Values ...>::type;
- m3ta::SubtractionResult
template<typename ... T_Values> using SubtractionResult = ArithmeticOperationResult<ArithmeticOperator::subtraction, T_Values ...>;
- m3ta::SubtractionResultT
template<typename ... T_Values> using SubtractionResultT = typename SubtractionResult<T_Values ...>::type;
- m3ta::MultiplicationResult
template<typename ... T_Values> using MultiplicationResult = ArithmeticOperationResult<ArithmeticOperator::multiplication, T_Values ...>;
- m3ta::MultiplicationResultT
template<typename ... T_Values> using MultiplicationResultT = typename MultiplicationResult<T_Values ...>::type;
- m3ta::DivisionResult
template<typename ... T_Values> using DivisionResult = ArithmeticOperationResult<ArithmeticOperator::division, T_Values ...>;
- m3ta::DivisionResultT
template<typename ... T_Values> using DivisionResultT = typename DivisionResult<T_Values ...>::type;
Usage Examples¶
using Type1 = m3ta::AdditionResultT<char, short>; // int
using Type2 = m3ta::SubtractionResultT<int, float>; // float
using Type3 = m3ta::ArithmeticOperationResultT<
m3ta::ArithmeticOperator::multiplication,
float,
std::complex<float>
>; // std::complex<float>
Concatenate Integer Sequences¶
#include <m3ta/concatenateintegersequences>
Concatenates two integer sequences into one.
Traits¶
- m3ta::ConcatenateIntegerSequences
template<typename T_Sequence1, typename T_Sequence2> struct ConcatenateIntegerSequences
Template Parameters: - T_Sequence1 – The first integer sequence.
- T_Sequence2 – The second integer sequence.
Member Types
- type
The type m3ta::IntegerSequence resulting of the concatenation.
Aliases¶
- m3ta::ConcatenateIntegerSequencesT
template<typename T_Sequence1, typename T_Sequence2> using ConcatenateIntegerSequencesT = typename ConcatenateIntegerSequences<T_Sequence1, T_Sequence2>::type;
Usage Examples¶
using Type = m3ta::ConcatenateIntegerSequencesT<
m3ta::IntegerSequence<int, 1, 2>,
m3ta::IntegerSequence<int, 3, 4>
>; // m3ta::IntegerSequence<int, 1, 2, 3, 4>
Extract Integer Sequence¶
#include <m3ta/extractintegersequence>
Extracts the integer sequence as an object instance, such as a std::array.
Traits¶
- m3ta::ExtractIntegerSequence
template<typename T_Sequence> struct ExtractIntegerSequence
Template Parameters: - T_Sequence – Integer sequence.
Member Functions
- std::array<T, sizeof ... (T_values)> asArray()
The integer sequence as a std::array.
Usage Examples¶
auto array = m3ta::ExtractIntegerSequence<
m3ta::IndexSequence<0, 1, 2, 4>
>::asArray(); // std::array<std::size_t, 4>
Nested Initializer Lists¶
#include <m3ta/nestedinitializerlists>
A given type wrapped within a number of nested std::initializer_list.
In other words, m3ta::NestedInitializerListsT<int, 2> is the same as std::initializer_list<std::initializer_list<int>>.
Traits¶
- m3ta::NestedInitializerLists
template<typename T, std::size_t T_levels> struct NestedInitializerLists
Template Parameters: - T – Inner type.
- T_levels – Number of std::initializer_list wrapping the type T.
Member Types
- type
The type of the outer std::initializer_list. Returns T if T_levels is 0.
Aliases¶
- m3ta::NestedInitializerListsT
template<typename T, std::size_t T_levels> using NestedInitializerListsT = typename NestedInitializerLists<T, T_levels>::type;
Usage Examples¶
using Type1 = m3ta::NestedInitializerListsT<int, 0>; // int
using Type2 = m3ta::NestedInitializerListsT<int, 1>; // std::initializer_list<int>
using Type3 = m3ta::NestedInitializerListsT<int, 2>; // std::initializer_list<std::initializer_list<int>>
Pass¶
#include <m3ta/pass>
Does nothing but passing the given template argument while taking an optional parameter pack.
This is a convenient way to test a SFINAE expression while always returning the required type.
See Also
Traits¶
- m3ta::Pass
template<typename T, typename ... T_Dummies> struct Pass
Template Parameters: - T – Type to pass.
- T_Dummies – Allows for some expressions to be ran through.
Member Types
- type
The type T.
Aliases¶
- m3ta::PassT
template<typename T, typename ... T_Dummies> using PassT = typename Pass<T, T_Dummies ...>::type;
Usage Examples¶
using Type1 = m3ta::PassT<void, int, float>; // void
using Type2 = m3ta::PassT<short, int, float>; // short
Pop Integer Sequence¶
#include <m3ta/popintegersequence>
Removes a given number of elements from the end of an integer sequence.
Traits¶
- m3ta::PopIntegerSequence
template<std::size_t T_count, typename T_Sequence> struct PopIntegerSequence;
Template Parameters: - T_count – Number of elements to remove from the end.
- T_Sequence – The integer sequence.
Member Types
- type
The type m3ta::IntegerSequence resulting of the elements removal.
Aliases¶
- m3ta::PopIntegerSequenceT
template<std::size_t T_count, typename T_Sequence> using PopIntegerSequenceT = typename PopIntegerSequence<T_count, T_Sequence>::type; template<std::size_t T_count, typename T, T ... T_values> using PopIntegerPack = PopIntegerSequence< T_count, IntegerSequence<T, T_values...> >; template<std::size_t T_count, typename T, T ... T_values> using PopIntegerPackT = typename PopIntegerPack<T_count, T, T_values ...>::type; template<std::size_t T_count, std::size_t ... T_values> using PopIndexPack = PopIntegerSequence< T_count, IndexSequence<T_values...> >; template<std::size_t T_count, std::size_t ... T_values> using PopIndexPackT = typename PopIndexPack<T_count, T_values ...>::type;
Usage Examples¶
using Type1 = m3ta::PopIndexPackT<
1,
0, 1, 2, 4
>; // m3ta::IntegerSequence<std::size_t, 0, 1, 2>
using Type2 = m3ta::PopIntegerSequenceT<
2,
m3ta::IntegerSequence<int, 0, 1, 2, 4>
>; // m3ta::IntegerSequence<int, 0, 1>
Read-Only Parameter¶
#include <m3ta/readonlyparameter>
Resolves the most optimal read-only parameter signature for a given type.
In other words, it returns either T or const T& depending on the size of a type T.
Note
Any const, volatile and reference qualifiers are ignored during the resolution. As such, the types T, T &&, const T &, and so on, will all resolve to the same type.
Traits¶
- m3ta::ReadOnlyParameter
template<typename T> struct ReadOnlyParameter
Template Parameters: - T – Type to resolve.
Member Types
- type
The most optimal read-only parameter signature for the type T.
Aliases¶
- m3ta::ReadOnlyParameterT
template<typename T> using ReadOnlyParameterT = typename ReadOnlyParameter<T>::type;
Usage Examples¶
using Type1 = m3ta::ReadOnlyParameterT<char>; // char
using Type2 = m3ta::ReadOnlyParameterT<std::complex<double>>; // const std::complex<double> &
using Type3 = m3ta::ReadOnlyParameterT<double *>; // double*
using Type4 = m3ta::ReadOnlyParameterT<double[32]>; // double[32]
using Type5 = m3ta::ReadOnlyParameterT<const volatile char &>; // char
using Type6 = m3ta::ReadOnlyParameterT<char &&>; // char
Remove Qualifiers¶
#include <m3ta/removequalifiers>
Removes any qualifiers from a given type.
Any const, volatile and reference qualifiers are removed. As such, the types T, T &&, const T &, and so on, will all resolve to T.
Arrays and pointers are preserved.
Traits¶
- m3ta::RemoveQualifiers
template<typename T> struct RemoveQualifiers
Template Parameters: - T – Type to remove the qualifiers from.
Member Types
- type
The type T without any qualifier.
Aliases¶
- m3ta::RemoveQualifiersT
template<typename T> using RemoveQualifiersT = typename RemoveQualifiers<T>::type;
Usage Examples¶
using Type1 = m3ta::RemoveQualifiersT<int>; // int
using Type2 = m3ta::RemoveQualifiersT<const volatile int &>; // int
using Type3 = m3ta::RemoveQualifiersT<int &&>; // int
using Type4 = m3ta::RemoveQualifiersT<int *&>; // int *
using Type5 = m3ta::RemoveQualifiersT<int[32]>; // int[32]
Reverse Integer Sequence¶
#include <m3ta/reverseintegersequence>
Reverses an integer sequence.
Traits¶
- m3ta::ReverseIntegerSequence
template<typename T_Sequence> struct ReverseIntegerSequence;
Template Parameters: - T_Sequence – Integer sequence.
Member Types
- type
The type m3ta::IntegerSequence resulting of the reversal.
Aliases¶
- m3ta::ReverseIntegerSequenceT
template<typename T_Sequence> using ReverseIntegerSequenceT = typename ReverseIntegerSequence<T_Sequence>::type; template<typename T, T ... T_values> using ReverseIntegerPack = ReverseIntegerSequence<IntegerSequence<T, T_values...>>; template<typename T, T ... T_values> using ReverseIntegerPackT = typename ReverseIntegerPack<T, T_values...>::type; template<std::size_t ... T_values> using ReverseIndexPack = ReverseIntegerSequence<IndexSequence<T_values...>>; template<std::size_t ... T_values> using ReverseIndexPackT = typename ReverseIndexPack<T_values...>::type;
Usage Examples¶
using Type1 = m3ta::ReverseIndexPackT<
0, 1, 2, 4
>; // m3ta::IntegerSequence<std::size_t, 4, 2, 1, 0>
using Type2 = m3ta::ReverseIntegerSequenceT<
m3ta::IntegerSequence<int, 0, 1, 2, 4>
>; // m3ta::IntegerSequence<int, 4, 2, 1, 0>
Specials¶
For the uncategorizable ones.
Dependent Bool¶
#include <m3ta/dependentbool>
Creates a dependency to some dummy types and returns a bool value.
See Also
Functions¶
- m3ta::dependentBool
template<typename ... T_Dummies> constexpr bool dependentBool(bool value) noexcept
Template Parameters: - T_Dummies — Types to trigger the dependency.
Function Parameters: - value – bool value to return.
Returns
The bool value passed as argument.
Usage Examples¶
bool value1 = m3ta::dependentBool<int, float>(true); // true
bool value2 = m3ta::dependentBool<int, float>(false); // false
Integer Sequence¶
#include <m3ta/integersequence>
Sequence of integers.
This is the equivalent of C++14’s std::integer_sequence.
Traits¶
- m3ta::IntegerSequence
template<typename T, T ... T_values> struct IntegerSequence
Template Parameters: - T – Type of the integer values.
- T_values – Integral values.
Member Types
- value_type
The type T.
Member Functions
- std::size_t size() noexcept
Number of values.
Aliases¶
- m3ta::IndexSequence
template<std::size_t ... T_values> using IndexSequence = IntegerSequence<std::size_t, T_values ...>;
Additional Information¶
FAQ¶
Why providing constexpr functions when traits would be enough?¶
Functions have a friendlier syntax and can be more flexible to use. Indeed, variadic functions accept a variable number of heterogeneous arguments while their trait counterpart only accept the values passed to the variadic non-type template parameters that can be implicitely converted to a same type. Furthermore, the non-type template parameters allowed are restricted to a smaller subset which do not include floating-points or custom types.
m3ta::all(true, 2, 4.0f); //< Valid.
m3ta::AllT<bool, true, 2, 4>::value; //< Valid, implicit conversions of int to bool.
m3ta::AllT<bool, true, 2, 4.0f>::value; //< Invalid due to the use of a float.
Why also providing traits on top of existing functions then?¶
Because functions can only return values, not types. Retrieving a constant value might be enough in most cases but not when used with the tag dispatching technique or in some SFINAE contexts where a type is expected to resolve which overload to use. Hence why each existing function is being wrapped into a trait inheriting from std::integral_constant.
See Also
Contributing¶
Found a bug or got a feature request? Don’t keep it for yourself, log a new issue on the GitHub project page.
Changes¶
v0.0.2 (2015-03-21)¶
- Add the ReverseIntegerSequence and ExtractIntegerSequence traits.
- Add aliases for integer parameter packs, such as PopIntegerPackT.
- Swapped the position of the T_Sequence and T_count template arguments for the PopIntegerSequence trait.
- Minor fixes.
v0.0.1 (2015-01-09)¶
- Initial release.
Versioning¶
Versions numbers will comply with the Sementic Versioning (SemVer) specification and will be written in the form <major>.<minor>.<patch>, where:
- backwards incompatible API changes increments the major version (and resets the minor and patch versions).
- backwards compatible API additions/changes increments the minor version (and resets the patch version).
- bug fixes not affecting the API increments the patch version.
License¶
The MIT License (MIT)
Copyright (c) 2015 Christopher Crouzet
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.