galmon/ext/CLI11/CLI/TypeTools.hpp

115 lines
3.3 KiB
C++

#pragma once
// Distributed under the 3-Clause BSD License. See accompanying
// file LICENSE or https://github.com/CLIUtils/CLI11 for details.
#include <exception>
#include <string>
#include <type_traits>
#include <vector>
namespace CLI {
// Type tools
// Copied from C++14
#if __cplusplus < 201402L
template <bool B, class T = void> using enable_if_t = typename std::enable_if<B, T>::type;
#else
// If your compiler supports C++14, you can use that definition instead
using std::enable_if_t;
#endif
template <typename T> struct is_vector { static const bool value = false; };
template <class T, class A> struct is_vector<std::vector<T, A>> { static bool const value = true; };
template <typename T> struct is_bool { static const bool value = false; };
template <> struct is_bool<bool> { static bool const value = true; };
namespace detail {
// Based generally on https://rmf.io/cxx11/almost-static-if
/// Simple empty scoped class
enum class enabler {};
/// An instance to use in EnableIf
constexpr enabler dummy = {};
// Type name print
/// Was going to be based on
/// http://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template
/// But this is cleaner and works better in this case
template <typename T,
enable_if_t<std::is_integral<T>::value && std::is_signed<T>::value, detail::enabler> = detail::dummy>
constexpr const char *type_name() {
return "INT";
}
template <typename T,
enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value, detail::enabler> = detail::dummy>
constexpr const char *type_name() {
return "UINT";
}
template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> = detail::dummy>
constexpr const char *type_name() {
return "FLOAT";
}
/// This one should not be used, since vector types print the internal type
template <typename T, enable_if_t<is_vector<T>::value, detail::enabler> = detail::dummy>
constexpr const char *type_name() {
return "VECTOR";
}
template <typename T,
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !is_vector<T>::value,
detail::enabler> = detail::dummy>
constexpr const char *type_name() {
return "TEXT";
}
// Lexical cast
/// Integers / enums
template <typename T,
enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value, detail::enabler> = detail::dummy>
bool lexical_cast(std::string input, T &output) {
try {
output = static_cast<T>(std::stoll(input));
return true;
} catch(const std::invalid_argument &) {
return false;
} catch(const std::out_of_range &) {
return false;
}
}
/// Floats
template <typename T, enable_if_t<std::is_floating_point<T>::value, detail::enabler> = detail::dummy>
bool lexical_cast(std::string input, T &output) {
try {
output = static_cast<T>(std::stold(input));
return true;
} catch(const std::invalid_argument &) {
return false;
} catch(const std::out_of_range &) {
return false;
}
}
/// String and similar
template <typename T,
enable_if_t<!std::is_floating_point<T>::value && !std::is_integral<T>::value && !std::is_enum<T>::value,
detail::enabler> = detail::dummy>
bool lexical_cast(std::string input, T &output) {
output = input;
return true;
}
} // namespace detail
} // namespace CLI