To be fair, this sort of thing doesn't have to be so much worse in C++ (yes, it would have been nice if it had been built into the language itself to begin with). You just need a function to do a back-and-forth conversion which then double-check the results, ie:
#include
#include
template
void convert_safely_helper_(From const& value, To& result) {
std::stringstream sst;
sst > result;
}
// Doesn't throw, just fails
template
bool convert_safely(From const& value, To* result) {
From check;
convert_safely_helper_(value, *result);
convert_safely_helper_(*result, check);
if (check != value) {
*result = To();
return false;
}
return true;
}
// Throws on error
template
To convert_safely(From const& value) {
To result;
if (!convert_safely(value, &result))
throw std::logic_error("invalid conversion");
return result;
}
#include
template
void sendOrder(const char* symbol, Buy buy, Quantity quantity, Price price) {
std::cout (buy) (quantity) (price)
void test(Function attempt) {
try {
attempt();
} catch (const std::exception& error) {
std::cout
Output:
sendOrder("GOOG", true, 100, 1000.0): GOOG 1 100 1000
sendOrder("GOOG", true, 100.0, 1000): GOOG 1 100 1000
sendOrder("GOOG", true, -100, 1000): GOOG 1 [Error: invalid conversion]
sendOrder("GOOG", true, 100.5, 1000): GOOG 1 [Error: invalid conversion]
sendOrder("GOOG", 2, 100, 1000): GOOG [Error: invalid conversion]
Rust of course leaves "less footguns laying around", but I still prefer to use C++ if I have my druthers.