5454#include  < charconv> 
5555#include  < cstring> 
5656#include  < iostream> 
57+ #include  < limits> 
5758#include  < optional> 
5859#include  < sstream> 
5960#include  < stdexcept> 
@@ -194,9 +195,14 @@ public:
194195      static_assert (std::is_integral_v<T> || std::is_floating_point_v<T>);
195196
196197      if  (auto  val = GetFlagValue (name); !val.empty ()) {
198+          //  NOTE: on paper std::from_chars is supported since C++17, however some compilers don't properly support it
199+          //  (e.g. it's not available at all on MacOS < 26 and only the integer overload is available in AlmaLinux 8).
200+          //  There is also no compiler define that we can use to determine the availability, so we just use it only
201+          //  from C++20 and hope for the best.
202+ #if  __cplusplus >= 202002L
197203         T converted;
198204         auto  res = std::from_chars (val.data (), val.data () + val.size (), converted);
199-          if  (res.ptr  == val.end () && res.ec  == std::errc{}) {
205+          if  (res.ptr  == val.data () + val. size () && res.ec  == std::errc{}) {
200206            return  converted;
201207         } else  {
202208            std::stringstream err;
@@ -211,6 +217,32 @@ public:
211217            else 
212218               throw  std::invalid_argument (err.str ());
213219         }
220+ #else 
221+          std::conditional_t <std::is_integral_v<T>, long  long , long  double > converted;
222+          std::size_t  unconvertedPos;
223+          if  constexpr  (std::is_integral_v<T>) {
224+             converted = std::stoll (std::string (val), &unconvertedPos);
225+          } else  {
226+             converted = std::stold (std::string (val), &unconvertedPos);
227+          }
228+ 
229+          const  bool  isOor = converted > std::numeric_limits<T>::max ();
230+          if  (unconvertedPos != val.size () || isOor) {
231+             std::stringstream err;
232+             err << " Failed to parse flag `" " ` with value `" " `" 
233+             if  constexpr  (std::is_integral_v<T>)
234+                err << "  as an integer.\n " 
235+             else 
236+                err << "  as a floating point number.\n " 
237+ 
238+             if  (isOor)
239+                throw  std::out_of_range (err.str ());
240+             else 
241+                throw  std::invalid_argument (err.str ());
242+          }
243+ 
244+          return  converted;
245+ #endif 
214246      }
215247      return  std::nullopt ;
216248   }
0 commit comments