Basically, I'd like to implement a float16
type. But this question is not about the details of how to do that, but instead how to set things up so that my new float16 type behaves appropriately with float, double, and all the integer types.
What I would like is for my float16
type to convert analogously as to float or double. For instance, it should implicitly cast to both of these types. It should also have std::common_type (http://en.cppreference.com/w/cpp/types/common_type) behaving analogously for it as it std::common_types behaves for the other float types. This means that std::common_type<my_float16, float>::type = float
, std::common_type<my_float16, double>::type = double
, and std::common_type<my_float16, T>::type = my_float16
where T
is any integer type.
What constructors and cast operators do I need to write to make this work? Any help would be appreciated!
My other recent question might be related.
EDIT: Okay, I've built a minimal example like Anton did. It is
struct float16 {
explicit operator int() {
return 0;
}
operator float() {
return 0.0f;
}
};
This has the right common type for float and float16, but the common type for int and float16 is still int. I do not understand that.
I don't think you can get this exactly, because the C++ core language treats natively defined conversion (e.g. char
to int
) differently from user defined conversion (even if they are implicit).
For example after
struct float16 { float16(int) {} }; // cast int->float16 is implicit
struct Foo { Foo(const double&){} }; // constructor accepts a double&
struct Bar { Bar(const float16&){} }; // constructor accepts a float16&
void foo(const Foo&) {}
void bar(const Bar&) {}
the call foo(3)
is valid because the integer 3
can be converted implicitly to a double
and foo
accepts a Foo
instance that can be constructed implicitly from a double
by a user-defined conversion (the Foo
constructor that is not explicit
).
However bar(3)
is not valid because such a call would require TWO implicit user-defined conversions (int
→float16
and float16
→Bar
) and this is not allowed.
If you implement it as a struct/class type, provide overloads of all the relevant operators and constructors. Look up the guidelines for what a class needed if it supports conversion both to and from other types.
If you want your class to play nicely with standard templates like std::common_type
and std::numeric_limits
, you will need to provide appropriate specialisation of those templates. It is probably best to read the actual standards for a description of requirements of such specialisations, but there is probably some tutorial material around (I have seen good introductory material for specialising std::numeric_limits
, but not for std::common_type
).
There will always be some limitations on how your type fits in with built-in standard types (int
, float
, etc) unless you use compiler-specific types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With