Wrapping numerical types in classes?

Started by
21 comments, last by ChaosEngine 11 years, 6 months ago

Just like if you made a fixed size array class. You dont create a class for each array size and then create separate template magic to retrieve data about it...

You realize that actual computer hardware works with set numbers of bits at a time, right? The reason why your average PC C++ compiler has 8-bit, 16-bit, 32-bit and (usually) 64-bit integers is because those are the number of bits that your CPU works with most efficiently at a time. There's no 13-bit integer type because your standard x86-family processor doesn't have any assembly operations that work with 13-bit operands. If you created your hypothetical integer template, then implementing that template would require some hardcore special template magic in order to work anywhere near efficiently.
Advertisement
You can get arbitrary-precision arithmetic libraries. One may some day be adopted into the standard library (propose it!). This sort of thing is not a part of the language proper because (1) C++ is a systems programming language, and arbitrary precision is not generally a system programming concept (although the fast_* and min_* integral types are system programming concepts) and (2) one of the fundamental design concepts of C++ is pay only for what you use and adding such support would add increased cost to everyone for very common operations to support a rare and little-used function.

Making primitive types more OO is not a goal of C++ either. C++ is not an "OO language," it's a multi-paradigm language that has OO support.

There's no reason why you can't write a library to do what you propose. It's unlikely to have enough widespread applicability to end up in the standard, but I would have thought the same thing of special numeric functions yet there they are. The usual place for such specialized things is an external library, though.

Stephen M. Webb
Professional Free Software Developer


but it would be nicer to have it directly in the class like with everything else
This is the C#/Java way of thinking ("corrupted OOP" IMO), where everything has to be in a class, not the C++ way of thinking.

The first way of thinking leads to #1 below, whereas #2 is more C++ style (in my experience).//#1
class Foo
{
public: int Bar( int );
void UtilityHelper() { Bar(42); }
private: int m_Baz;
};
//#2
class Foo
{
public: int Bar( int );
private: int m_Baz;
};
void UtilityHelper(Foo& foo) { foo.Bar(42); }
The reason is that in #1, the private details such as [font=courier new,courier,monospace]m_Baz[/font] have been unnecessarily exposed to the utility/helper function. This means that if you're investigating a bug involving [font=courier new,courier,monospace]m_Baz[/font], then you have to treat [font=courier new,courier,monospace]UtilityHelper[/font] as a suspect, increasing the amount of code to read/maintain.
In the 2nd style, the utility is known to only have access to the public interface, not the private details.
The number of bits passed down into the example integer<bits> would of course find the smallest integer type that has at least that many bits and is native to the processor.

Maybe utility functions werent a good idea to put there, but is there any major reasons why not to make a class like

integer<minimumBits> (or bytes?)

where it internally has a typedef for the primitive data type to use, and specialized operator etc. templates for each type? (if needed, probably a single template is fine for char, short and int...)

So basically just a class to make the different integer types a single class for the sole purpose of being able to pass in the amount of bits needed and get the best type for it.

C++ guarantees each of the primitive types to have some amount of bits, which probably was fine in C when the programmer had to copy the code anyways if lets say dimension or size changed, but now with templates the computer should do it, which in my opinion is easiest to achieve by making the integers template classes. This also makes them all carry their bit count with them, and doesnt require external template classes to lets say pick tge best integer type for a number of bits or to get the number of bits...

o3o

Boost has a class to make integer type selection based on size; boost::int_t<N>. It has three nested typedefs; fast, least and exact, representing the fastest type with at least N bits, the smallest type than can accommodate at least N bits, and a type with exactly N bits. The exact typedef is only available if there actually is a type with that many bits though.

[quote name='Waterlimon' timestamp='1350931178' post='4992843']
but it would be nicer to have it directly in the class like with everything else
This is the C#/Java way of thinking ("corrupted OOP" IMO), where everything has to be in a class, not the C++ way of thinking.

The first way of thinking leads to #1 below, whereas #2 is more C++ style (in my experience).//#1
class Foo
{
public: int Bar( int );
static void UtilityHelper() { Bar(42); }
private: int m_Baz;
};
//#2
class Foo
{
public: int Bar( int );
private: int m_Baz;
};
void UtilityHelper(Foo&amp; foo) { foo.Bar(42); }
The reason is that in #1, the private details such as [font=courier new,courier,monospace]m_Baz[/font] have been unnecessarily exposed to the utility/helper function. This means that if you're investigating a bug involving [font=courier new,courier,monospace]m_Baz[/font], then you have to treat [font=courier new,courier,monospace]UtilityHelper[/font] as a suspect, increasing the amount of code to read/maintain.
In the 2nd style, the utility is known to only have access to the public interface, not the private details.
[/quote]

Does #1 actually work; on what instance is Bar invoked?
I think that as Brother Bob said std::numeric_limits should serve your purpose. However, I don't think wrapping numeric types in templates would be a bad idea otherwise. I'm doing it for atomic variables.

I think that as Brother Bob said std::numeric_limits should serve your purpose. However, I don't think wrapping numeric types in templates would be a bad idea otherwise. I'm doing it for atomic variables.

The way [font=courier new,courier,monospace]std::atomic[/font] does?

Stephen M. Webb
Professional Free Software Developer

Yeah. Except std::atomic is C++ 11 and I'm not using C++ 11 features in my project because of portability.
Don't forget [font=courier new,courier,monospace]std::atomic[/font] is a part of the current C++ standard. If your compiler does not support the current C++ standard, it's a non-compliant compiler. Why are you using a non-standard compiler?

Stephen M. Webb
Professional Free Software Developer

This topic is closed to new replies.

Advertisement