Last active
January 1, 2024 06:11
-
-
Save dlOuOlb/f21c082e850750500c0baa8a223d4b66 to your computer and use it in GitHub Desktop.
A function template about checked integer casting.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if __cplusplus < 202002L | |
# error "This code is written in C++20." | |
#else | |
export module dlOuOlb.numeric:checked_cast; | |
import <format>; /* std::format */ | |
import <limits>; /* std::numeric_limits */ | |
import <stdexcept>; /* std::(overflow|underflow)_error */ | |
import <string>; /* std::(to_)?string */ | |
namespace dlOuOlb::numeric | |
{ | |
template<class Integer> requires | |
std::numeric_limits<Integer>::is_integer | |
static const std::string description = | |
std::format | |
( | |
R"({1} {0}-digit integer)", | |
std::numeric_limits<Integer>::digits, | |
std::numeric_limits<Integer>::is_signed? R"(signed)": R"(unsigned)" | |
); | |
template<class Target, class Source> requires | |
std::numeric_limits<Target>::is_integer && | |
std::numeric_limits<Source>::is_integer | |
static auto explain( const Source Value ) noexcept( false )->std::string | |
{ | |
return std::format | |
( | |
R"({2:+#X} cannot be preserved when being casted from {1} to {0}.)", | |
description<Target>, | |
description<Source>, | |
Value | |
); | |
} | |
export extern R"(C++)" | |
template<class Target, class Source> requires | |
std::numeric_limits<Target>::is_integer && | |
std::numeric_limits<Source>::is_integer | |
constexpr auto checked_cast( const Source Value ) noexcept | |
( | |
std::numeric_limits<Source>::digits <= std::numeric_limits<Target>::digits && | |
( | |
std::numeric_limits<Target>::is_signed || | |
!std::numeric_limits<Source>::is_signed | |
) | |
)->Target | |
{ | |
if constexpr( !std::numeric_limits<Source>::is_signed ) | |
if constexpr( std::numeric_limits<Source>::digits <= std::numeric_limits<Target>::digits ) | |
return static_cast<Target>( Value ); | |
else if( static_cast<Source>( std::numeric_limits<Target>::max( ) ) < Value ) | |
throw std::overflow_error { explain<Target>( Value ) }; | |
else | |
return static_cast<Target>( Value ); | |
else if constexpr( std::numeric_limits<Target>::is_signed ) | |
if constexpr( std::numeric_limits<Source>::digits <= std::numeric_limits<Target>::digits ) | |
return static_cast<Target>( Value ); | |
else if( Value < static_cast<Source>( std::numeric_limits<Target>::min( ) ) ) | |
throw std::underflow_error { explain<Target>( Value ) }; | |
else if( static_cast<Source>( std::numeric_limits<Target>::max( ) ) < Value ) | |
throw std::overflow_error { explain<Target>( Value ) }; | |
else | |
return static_cast<Target>( Value ); | |
else | |
if( Value < 0 ) | |
throw std::underflow_error { explain<Target>( Value ) }; | |
else if constexpr( std::numeric_limits<Source>::digits <= std::numeric_limits<Target>::digits ) | |
return static_cast<Target>( Value ); | |
else if( static_cast<Source>( std::numeric_limits<Target>::max( ) ) < Value ) | |
throw std::overflow_error { explain<Target>( Value ) }; | |
else | |
return static_cast<Target>( Value ); | |
} | |
} | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if __cplusplus < 202002L | |
# error "This code is written in C++20." | |
#else | |
export module dlOuOlb.numeric; | |
export import:checked_cast; | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if __cplusplus < 202002L | |
# error "This code is written in C++20." | |
#else | |
# include <iostream> /* std::(cerr|cout|endl) */ | |
# include <stdexcept> /* std::(overflow|underflow)_error */ | |
import dlOuOlb.numeric; /* dlOuOlb::numeric */ | |
extern R"(C++)" auto main( void ) noexcept( false )->signed int | |
{ | |
namespace S = std; | |
namespace OuO = dlOuOlb; | |
try | |
{ | |
const constexpr signed long int Source = __cplusplus; | |
const unsigned short int Target = OuO::numeric::checked_cast<decltype( Target )>( Source ); | |
static_cast<void>( S::cout << R"(__cplusplus : )" << Target << S::endl ); | |
} | |
catch( const S::overflow_error &Error ) | |
{ | |
static_cast<void>( S::cerr << Error.what( ) << S::endl ); | |
} | |
catch( const S::underflow_error &Error ) | |
{ | |
static_cast<void>( S::cerr << Error.what( ) << S::endl ); | |
} | |
{ | |
return 0; | |
} | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment