Skip to content

Instantly share code, notes, and snippets.

@pyrtsa
Created May 12, 2011 07:53
Show Gist options
  • Save pyrtsa/968125 to your computer and use it in GitHub Desktop.
Save pyrtsa/968125 to your computer and use it in GitHub Desktop.
Sketching the interface for the Boost.Coerce library
// === The planned interface (work in progress) ================================
namespace boost { namespace coerce {
// Does traits::as<T,S> provide the interface for extending the library?
namespace traits {
template <typename Target, typename Source, typename Enable = void>
struct as;
}
class bad_cast : public std::bad_cast {};
template <typename Target, typename Source>
Target as(Source const & source); // throws on failure
template <typename Target, typename Source>
optional<Target> as_optional(Source const & source); // won't throw
// Might not be needed; equivalent to: as_optional<T>(x).get_value_or(t)
template <typename Target, typename Source>
Target as_default(Source const & source, Target const & default_);
// Ugly interface for those who don't default construct *)
template <typename Target, typename Source>
bool convert_to(Target & target, Source const & source); // true on success
// ________
// *) I don't think types with no default constructor should be first class
// citizens for this library. The last interface, however, allows one to use
// the same machinery to convert to a non-default-constructible type.
}}
// (skipping includes etc.)
namespace coerce = boost::coerce;
struct lacking_default_ctor {
int value;
explicit lacking_default_ctor(int value) : value(value) {}
};
BOOST_FUSION_ADAPT_STRUCT(lacking_default_ctor, (int, value))
std::string value = "2.5";
// --- begin examples ----------------------------------------------------------
// Examples 1 and 2a are probably the most common cases.
try {
int i = coerce::as<int>(value); /* example 1 */
// ...
} catch (coerce::bad_cast &) {
// ...
}
boost::optional<double> d1 = coerce::as_optional<double>("1."); /* example 2a */
// Works pretty readably with auto:
auto d2 = coerce::as_optional<double>("123.4"); /* example 2b */
// as_optional competes with as_default, even if 14 chars longer:
double d3 = coerce::as_optional<double>(value).get_value_or(0); /* example 2c */
double d4 = coerce::as_default<double>(value, 0);
// Alternative use for as_optional:
if (auto d = coerce::as_optional<double>(value)) { /* example 2d */
std::cout << "Converted " << value << " to: " << d.get() << std::endl;
} else {
std::cerr << "Failed to convert " << value << " to double!" << std::endl;
}
float f = coerce::as_default<float>("1.2.3", 1.0f); /* example 3 */
lacking_default_ctor lack(-1);
if (coerce::convert_to(lack, "123")) { /* example 4 */
// ok
} else {
// handle error
}

Random thoughts

  • as<T>(s) and as_optional<T>(s) read quite well, convert_to(t, s) is not bad either
  • this interface still lacks the possibility to specify an own qi/karma format, but they could be possibly added as optional arguments for the functions as<T>(s, [in], [out]), as_optional<T>(s, [in], [out]) and convert_to(t, s, [in], [out])
    • that, however, can make the interface already quite a bit more complicated…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment