## constexpr - one of the most undervalued feature in modern C++ (1) * constexpr was introduced in C++11 * constexpr values are know during compilation process * Function also could be constexpr with some restriction: * they may only have exactly one statement and this statement had to be a return statement * not allowed to have any side effects, like if-else * not allowed to have exception and try-catch block * can use ternary operator * Usually wrote recurent rather then iterative functions * Functions behave like normal functions (not solved during compilation) when working with non-constexpr arguments * Class/ struct could have constexpr C'tor and member functions * In C++14 introduced: * Less restrictions for functions: * more then one return * can use if-else ___ ### constexpr - one of the most undervalued feature in modern C++ (2) * In C++17 introduced: * constexpr class string_view * constexpr std::array * constexpr iterator for array and std::begin, std::end functions * constexpr lambda * In C++20 introduced: * constexpr STL algorithms * constexpr std::vector and std::string and their iterators. (not supported by clang and gcc. Surprisely its supported by MSVC STL) * Allow to use try-catch in constexpr functions * Allow to allocate and deallocate values on heap, but need to free them before exit function * Allow to create virtual functions * Allow to use asm code block ___ ## C++11 constexpr function ```C++ #include constexpr bool isLower(char c) { return c >= 'a' && c <= 'z'; } template constexpr size_t countLower(const T (&str)[N], size_t current, size_t counter) { return current == N ? counter : isLower(str[current]) ? countLower(str, current + 1, counter + 1) : countLower(str, current + 1, counter); } int main() { static_assert(9 == countLower("Ala has a cat", 0, 0)); } ``` ```Bash xor eax,eax ret nop WORD PTR cs:[rax+rax*1+0x0] nop DWORD PTR [rax] ```
check on https://godbolt.org/
___ ## C++14 constexpr function ```C++ constexpr bool isLower(char c) { return c >= 'a' && c <= 'z'; } template constexpr size_t countLower(const T (&str)[N]) { size_t counter = 0; for (auto c : str) { if (isLower(c)) { ++counter; } } return counter; } int main() { static_assert(9 == countLower("Ala has a cat")); } ``` ```Bash xor eax,eax ret nop WORD PTR cs:[rax+rax*1+0x0] nop DWORD PTR [rax] ```
check on https://godbolt.org/
___ ## C++17 constexpr function (1) ```C++ template constexpr size_t countLower(const T (&str)[N]) { constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; }; size_t counter = 0; for (auto c : str) { if (isLower(c)) { ++counter; } } return counter; } int main() { static_assert(9 == countLower("Ala has a cat")); } ``` ```Bash xor eax,eax ret nop WORD PTR cs:[rax+rax*1+0x0] nop DWORD PTR [rax] ```
check on https://godbolt.org/
___ ## C++17 constexpr function (2) ```C++ constexpr size_t countLower(const std::string_view& str) { constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; }; size_t counter = 0; for (size_t i = 0 ; i < str.size() ; ++i) { if (isLower(str[i])) { ++counter; } } return counter; } int main() { static_assert(9 == countLower("Ala has a cat")); } ``` ```Bash xor eax,eax ret cs nop WORD PTR [rax+rax*1+0x0] nop DWORD PTR [rax] ```
check on https://godbolt.org/
___ ## C++20 constexpr function ```C++ constexpr size_t countLower(const std::string& str) { constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; }; size_t counter = 0; for (size_t i = 0 ; i < str.size() ; ++i) { if (isLower(str[i])) { ++counter; } } return counter; } int main() { static_assert(9 == countLower(std::string("Ala has a cat"))); } ```
check on https://en.cppreference.com/w/cpp/compiler_support
___ ## C++20 constexpr function - algorithms ```C++ constexpr size_t countLower(const std::string& str) { constexpr auto isLower = [](char c) { return c >= 'a' && c <= 'z'; }; return std::count_if(cbegin(str), cend(str), isLower); } int main() { static_assert(9 == countLower(std::string("Ala has a cat"))); } ```
check on https://en.cppreference.com/w/cpp/compiler_support
___ ## C++20 constexpr - allocation on heap (1) ```C++ template constexpr std::array generatePseudoRandom(int from, int to) { std::array arr; const int seed = ((N << 1) ^ (from << to) ^ to) ^ ((from + to) ^ (N << 3)); const size_t size = to - from; auto tmp = new int[size]; std::iota(tmp, tmp + size, from); for (int i = 0; i < N; ++i) { arr[i] = tmp[(seed ^ i) % size]; } delete[] tmp; return arr; } int main() { static_assert(generatePseudoRandom(10, 20).size() == 10); } ``` ```C++ Will print: 18 19 16 17 14 15 12 13 10 11 ``` ```Bash xor eax,eax ret cs nop WORD PTR [rax+rax*1+0x0] nop DWORD PTR [rax] ``` ___ ## C++20 constexpr - allocation on heap (1) If we forget to add delete[], compiler will detect it! ```C++ template constexpr std::array generatePseudoRandom(int from, int to) { std::array arr; const int seed = ((N << 1) ^ (from << to) ^ to) ^ ((from + to) ^ (N << 3)); const size_t size = to - from; auto tmp = new int[size]; std::iota(tmp, tmp + size, from); for (int i = 0; i < N; ++i) { arr[i] = tmp[(seed ^ i) % size]; } //delete[] tmp; return arr; } int main() { static_assert(generatePseudoRandom(10, 20).size() == 10); } ``` ```C++ : In function 'int main()': :22:64: error: non-constant condition for static assertion 22 | static_assert(generatePseudoRandom(10, 20).size() == 10); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ :10:16: error: '(generatePseudoRandom(10, 20).std::array::size() == 10)' is not a constant expression because allocated storage has not been deallocated 10 | auto tmp = new int[size]; | ^~~~~~~~~~~~~ Execution build compiler returned: 1 ``` ___ ### contexpr-if (1) * Who uses SFINAE? * Who likes SFINAE? ```C++ namespace { constexpr double epsilon = 0.000001; } template constexpr std::enable_if_t, bool> equal(T lhs, T rhs) { return std::abs(lhs - rhs) < epsilon; } template constexpr std::enable_if_t, bool> equal(T lhs, T rhs) { return lhs == rhs; } int main() { static_assert(equal(10, 10) == true); static_assert(equal(10.123f, 10.123f) == true); static_assert(equal(10.45678, 10.45678) == true); } ``` ```C++ xor eax,eax ret cs nop WORD PTR [rax+rax*1+0x0] nop DWORD PTR [rax] ``` ___ ### contexpr-if (2) ```C++ template constexpr bool equal(T lhs, T rhs) { constexpr double epsilon = 0.000001; if constexpr (std::is_floating_point_v) { return std::abs(lhs - rhs) < epsilon; } else { return lhs == rhs; } } int main() { static_assert(equal(10, 10) == true); static_assert(equal(10.123f, 10.123f) == true); static_assert(equal(10.45678, 10.45678) == true); } ``` ```C++ xor eax,eax ret cs nop WORD PTR [rax+rax*1+0x0] nop DWORD PTR [rax] ``` ___ ### C++20 concept ```C++ template requires std::is_floating_point_v constexpr bool equal(T lhs, T rhs) { constexpr double epsilon = 0.000001; return std::abs(lhs - rhs) < epsilon; } // Work only, when both types are equal! constexpr bool equal(auto lhs, auto rhs) { return lhs == rhs; } int main() { static_assert(equal(10, 10) == true); static_assert(equal(10.123f, 10.123f) == true); static_assert(equal(10.45678, 10.45678) == true); } ``` ```C++ xor eax,eax ret cs nop WORD PTR [rax+rax*1+0x0] nop DWORD PTR [rax] ```