Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C++11, how can I implement an arithmetic type that fits into the hierarchy of builtin types?

Tags:

c++

std

c++11

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.

like image 308
user2333829 Avatar asked Jun 21 '15 12:06

user2333829


2 Answers

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 (intfloat16 and float16Bar) and this is not allowed.

like image 87
6502 Avatar answered Oct 22 '22 20:10

6502


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.

like image 29
Peter Avatar answered Oct 22 '22 21:10

Peter