On 05/20/2014 09:15 PM, alex wrote:
Conversion to/from string requires a different contract than conversion between types, encryption or conversion from Celsius to Fahrenheit. I fail to see how/why these mentioned different type conversions/transformations "require different contracts".
Perhaps it is better to say 'would benefit from different contracts'.
For instance:
type-to-type converters would benefit from contracts that specify mechanisms for checking for reversibility, loss of precision, overflow, etc. type-string converters would benefit from contracts that specify mechanisms for giving formatting instructions unit-to-unit converters would benefit from all kinds of consistency and equivalence test... see the Boost Unit library encryptions converters would benefit from contracts that specify mechanisms to specify/query encryption strength
I am not arguing against interface/behavior specifications (a.k.a. "contracts") for converters. I only feel that "convert"'s purpose is far more modest -- to only specify how to deploy various converters and what to expect when we do. It seems far beyond my capabilities and expertise to come up with "contracts" you listed.
The user still needs to supply a Default Construction function it is just not the default constructor. I can see that this requirement follows from the stringstream implementation. No, it's not a requirement of std::sstream but rather imposed by boost::convert::from.
Yes, but why? Isn't the underlying reason that sstream requires a reference?
my_type val; stream >> val;
I feel it's a generic converter requirement -- they all need a "place" to write the result to. We might say -- every converter for itself. On the other hand, that seemed like a generic enough requirement that the "framework" might care providing uniformly to every converter.
But it does not seem a reasonable requirement for a generic converter (nor is the requirement of Copy Constructible). All you can reasonably require is some function that creates a TypeOut from a TypeIn.
Well, I feel you are not avoiding requirements but merely shifting them around from boost::convert() down to converters. A converter will still need to be able to create and TypeOut instance somehow and in a generic way. So, I feel, we'll be back where we are now with the burden of every converter having to do it itself.
I was not able to come up with a better implementation that would not have those requirements. If you have such an implementation, I'll incorporate it gladly.
How about reducing the API to the following? The only requirement on TypeOut would be the requirements put by boost::optional (or your closely related result-type).
api.hpp #include
namespace boost template<typename TypeOut> struct convert template static boost::optional<TypeOut> from(TypeIn const& in, Converter const& converter) { boost::optional<TypeOut> out; converter(in, out); return out; } }; } In sstream.hpp you would have(with some simplification)
template<typename T> struct convert_default_maker { static T make() { return T(); } };
That seems like a 0-gain game as we still have all the same requirements and all the same code, right? We still ned to be able to create a TypeOut instance somehow generically. Although the code above forces every converter to do that by themselves, right? Although passing boost::optional into a container might have its benefits... I had it at one point... will have to re-visit again.
// in sstream.hpp template
void boost::basic_stringstream_converter::operator()(const TypeIn& in, boost::optional<TypeOut>& out) { TypeOut out_value = boost::convert_default_maker<TypeOut>::make(); stream_.str(std::basic_string< char_type>()); stream_ << in; stream_ >> out_value; out = boost::make_optional(!stream_.fail(), out_value); }
That's something I'll have to think about. What jumps at me though is what I'd call "blur of responsibilities" -- now converter not only cares for conversion but for allocation as well. Secondly, in the current "convert" design converters know nothing about boost::convert "framework". The implementation above seems to require the converter to know/deploy boost::converter_default_maker which is either part of the "convert" infrastructure or converter's own code, i.e. the converter has to have either additional "knowledge"/coupling or additional code. In both cases I do not like the "additional" bit. :-)