I want to make the following function a function template that supports all the integral types:
#include <iostream>
#include <utility>
#include <charconv>
#include <string_view>
#include <concepts>
#include <limits>
#include <optional>
// header file
std::optional<int> to_integer( std::string_view token, const std::pair<int, int> acceptableRange =
{ std::numeric_limits<int>::min( ), std::numeric_limits<int>::max( ) } ) noexcept;
std::optional<int> to_integer( const char* const token, const std::pair<int, int> acceptableRange =
{ std::numeric_limits<int>::min( ), std::numeric_limits<int>::max( ) } ) noexcept = delete;
// source file
std::optional<int> to_integer( std::string_view token, const std::pair<int, int> acceptableRange ) noexcept
{
if ( token.empty( ) )
{
return { };
}
if ( token.size( ) > 1 && token[ 0 ] == '+' && token[ 1 ] != '-' ) { token.remove_prefix( 1 ); }
int value;
const auto [ ptr, ec ] { std::from_chars( token.begin( ), token.end( ), value, 10 ) };
const auto& [ minAcceptableValue, maxAcceptableValue ] { acceptableRange };
if ( ec != std::errc( ) || ptr != token.end( ) ||
value < minAcceptableValue || value > maxAcceptableValue ) { return { }; }
return value;
}
Here is my version:
// header file
template < std::integral T >
std::optional<T> to_integer( std::string_view token, const std::pair<T, T> acceptableRange =
{ std::numeric_limits<T>::min( ), std::numeric_limits<T>::max( ) } ) noexcept;
template < std::integral T >
std::optional<T> to_integer( const char* const token, const std::pair<T, T> acceptableRange =
{ std::numeric_limits<T>::min( ), std::numeric_limits<T>::max( ) } ) noexcept = delete;
// source file
template < std::integral T >
std::optional<T> to_integer( std::string_view token, const std::pair<T, T> acceptableRange ) noexcept
{
if ( token.empty( ) )
{
return { };
}
if ( token.size( ) > 1 && token[ 0 ] == '+' && token[ 1 ] != '-' ) { token.remove_prefix( 1 ); }
T value;
const auto [ ptr, ec ] { std::from_chars( token.begin( ), token.end( ), value, 10 ) };
const auto& [ minAcceptableValue, maxAcceptableValue ] { acceptableRange };
if ( ec != std::errc( ) || ptr != token.end( ) ||
value < minAcceptableValue || value > maxAcceptableValue ) { return { }; }
return value;
}
// call site
int main( )
{
const std::string_view sv { "-100" };
const auto retVal { to_integer<unsigned int>( sv, { 0, 100 } ) };
std::cout << retVal.value_or( -1 ) << '\n';
}
- Does my implementation have any flaws? Can it fail in some cases? How would you write it to make it better?
- It somehow returns 4294967295 when passing e.g. "-100" as can be seen in the
main
function. Why? How can I fix that? I expect it to return an emptyoptional
since -100 is out of range ofunsigned int
.