I'm working on a design implementation where I want the input to be selected from a specific set of characters for its string literal representation.
Consider the following set of classes:
class enum BaseType {
BINARY = 2,
OCTAL = 8,
DECIMAL = 10,
HEXADECIMAL = 16
};
template<BaseType BASE = BaseType::DECIMAL> // Default Template
class Foo {
public:
const uint16_t Base{BASE};
private:
std::string digits_;
int64_t integral_value_;
int64_t decimal_value_;
size_t decimal_index_location_;
public:
Foo()
: digits_{""},
integral_value_{0},
decimal_value_{0}
decimal_index_location_{0}
{}
Foo(const std::string_view digit_sequence)
: digits_{digit_sequence},
integral_value_{0},
decimal_value_{0}
decimal_index_location{0}
{
// set values according to the respective digits
// from the decimal point if one exists
// and set the decimal index location if one exists...
}
};
I may have to use specializations for the other non-default types which have yet to be decided. Regardless of that, I want to restrict each case to the following character set as follows:
BINARY
:
'0'
, '1'
, '.'
OCTAL
:
['0' - '7']
, '.'
DECIMAL
:
['0' - '9']
, '.'
HEXADECIMAL
:
['0' - '9']
, ['a' - 'f']
, ['A' - 'F']
, '.'
These would be acceptable inputs for each type:
BINARY
:
"010"
, ".010"
, "01.0"
, "01.
" etc...OCTAL
:
"012345670"
, ".012345670"
, "01.2345670"
, "1."
, etc...DECIMAL
:
"01234567890"
, ".01234567890"
, "01.234567890"
, "1."
, etc...HEXADECIMAL
:
"0123456789abcdef0"
, ".0123456789abcdef0"
, "01.23456789abcdef0"
, "1."
, etc..."0123456789ABCDEF0"
, ".0123456789ABCDEF0"
, "01.23456789ABCDEF0"
, "1."
, etc...To be the only valid set of input characters for the string_view
parameter of the class's constructor.
Is there a simple, elegant, and efficient way of doing this? If so, how? It doesn't really matter if this is handled by throwing exceptions, compile-time or run-time assertions... I just want to limit the possible set of valid characters for each templated version...
EDIT
For each of the cases even a single '.'
is valid input. For example:
Foo a(".");
Would be interpreted as 0
and later when I incorporate the exponent
part, the exponent would evaluate to 1
so that the result would be 0
and not 1
due to power rules...
With <regex>
, you might do:
static const std::regex binary_regex(R"([01]*\.?[01]*)");
static const std::regex octal_regex(R"([0-7]*\.?[0-7]*)");
static const std::regex decimal_regex(R"([0-9]*\.?[0-9]*)");
static const std::regex hex_regex(R"([0-9a-fA-F]*\.?[0-9a-fA-F]*)");
bool do_match(const std::string& s, const std::regex& regex)
{
// if (s.empty()) { return false; }
std::smatch base_match;
return std::regex_match(s, base_match, regex);
}
You might even with grouping get the value before dot and after dot