Multiple Integer-type classes in C++ - c++

I often find myself using Integers to represent values in different "spaces". For example...
int arrayIndex;
int usersAge;
int daysToChristmas;
Ideally, I'd like to have separate classes for each of these types "Index","Years" and "Days", which should prevent me accidentally mixing them up. Typedefs are a help from a documnentation perspective, but aren't type-safe enough.
I've tried wrapper classes, but end up with too much boilerplate for my liking. Is there a straightforward template-based solution, or maybe something ready-to-go in Boost?
EDIT: Several people have talked about bounds-checking in their answers. That maybe a handy side-effect, but is NOT a key requirement. In particular, I don't just want to prevent out-of-bound assignments, but assignments between "inappropriate" types.

Boost does in fact have a library specifically for this type of thing! Check out the Boost.Units library.

One funky "hack" you could use is a template non-type parameter to create wrapper types. This doesn't add any bounds but it does allow to treat them as different types with only one set of boilerplate template code. I.e.
template<unsigned i>
class t_integer_wrapper
{
private:
int m_value;
public:
// Constructors, accessors, operators, etc.
};
typedef t_integer_wrapper<1> ArrayIndex;
typedef t_integer_wrapper<2> UsersAge;
Extend the template with lower and upper bounds or other validation as you like. Not pretty by a long shot though.

You could try BOOST_STRONG_TYPEDEF. From boost/strong_typedef.hpp:
// macro used to implement a strong typedef. strong typedef
// guarentees that two types are distinguised even though the
// share the same underlying implementation. typedef does not create
// a new type. BOOST_STRONG_TYPEDEF(T, D) creates a new type named D
// that operates as a type T.

I remember solving a similar problem with a simple template where you would specify the allowed range, i.e.
Int<0, 365> daysToChristmas;
Int<0, 150> usersAge;
Int<0, 6> dayOfWeek;
You get the point. Now you could just derive from such a template type, like
class DayOfYear: public Int<0, 365> {}
and you could no longer pass a user age to a function expecting a DayOfYear, and you wouldn't have to use the angled brackets.

This is a generic "StrongType" template that we use to wrap different types and contexts. The only significant difference to this answer is that we prefer to use a tag-type that gives a meaningful name to each specialized wrapper type:
template <typename ValueType, class Tag> class StrongType {
public:
inline StrongType() : m_value(){}
inline explicit StrongType(ValueType const &val) : m_value(val) {}
inline operator ValueType () const {return m_value; }
inline StrongType & operator=(StrongType const &newVal) {
m_value = newVal.m_value;
return *this;
}
private:
//
// data
ValueType m_value;
};
And a use of the template as follows:
class ArrayIndexTag;
typedef StringType<int, ArrayIndexTag> StrongArrayIndex;
StringArrayIndex arrayIndex;
Notice too, that all of the functions are 'inline', the intention being that the compiler can do its best to generate exactly the same code it would generated had the template not been used at all!

In addition to the Boost Units library mentioned by Ryan Fox, there will be also the Boost Constrained Value library, which is currently under review.
Who knows when or if it will hit an official Boost release, but you can probably try it out anyway.

Adding in the operator int () will allow you to use the object where a normal int is required. You can also add in a operator = () to set it within range.
class DayType
{
public:
static int const low = 1;
static int const high = 365;
};
template<class TYPE>
class Int
{
private:
int m_value;
public:
operator int () { return m_value; }
operator = ( int i ) { /* check and set*/ }
};
Int<DayType> day;
int d = day;
day = 23;
I hope this helps.

int arrayIndex;
This is what std::size_t is for.
int usersAge;
People can't have negative ages and it is not useful/easy to set a fixed upper bound for ages. So here you should just use unsigned int.
int daysToChristmas;
Days to Christmas requires special attention. The number of days until Christamas can range from 0-366. The simple solution is to write the following wherever needed:
assert( 0 < daysToChristmas && daysToChristmas < 366 )
If you feel you're going to duplicate that assert in too many places, then David Allan Finch proposes a neat solution for this case. Though I am partial to using the assert.

For an array index I'd use size_t provided I didn't need negative values, because that's what it's there for. Of course that frequently is unsigned int, so won't give you any type safety at all. However, anything that did give you type safety (i.e. that stopped you assigning an unsigned int to an array index) would also stop you returning a size_t value into your type. That might be too much type safety anyway.
You could probably use an enum for bounded ranges:
enum YearDay {
FirstJan = 0,
LastDecInLeapYear = 365
};
You can assign YearDay to int, but you can't assign an int (or another enum type) to YearDay without an explicit cast. Any value between the least and greatest named value in an enum is a valid value for the enum. Assigning a value outside the range [0,365] results in undefined behaviour. Or possibly an unspecified or implementation-defined result, I can't remember.
Age is tricky, because it's almost bounded, but not quite. You could use 969 (age of Methuselah) in an enum, or a class wrapping an int with explicit conversions as described by others.

Check out this old CUJ article on this subject. IIRC the technique desribes how to make it work with all the fundamental operators

Related

Named parameters of integral types through enumeration types

Consider the following code:
template<int complexity>
class Widget
{
public:
Widget(int size);
};
int main()
{
Widget<4> widget(12); // not easily readable if definition of Widget in some faraway header
return 0;
}
Another try using conversion to enumeration type as named parameters:
enum ComplexityInt : int {};
enum SizeInt : int {};
template<ComplexityInt complexity>
class Widget
{
public:
Widget(SizeInt size);
};
int main()
{
Widget<(ComplexityInt) 4> widget((SizeInt) 12);
return 0;
}
Is the second example completely fine C++ code without some undesirable side effects or additional costs? And what are your thoughts about it from the style and readability perspectives?
There is 2 different/orthogonal things to consider (I take Rectangle as example):
Do you want to name parameters? (as Height/Width)
Named parameters add a better expressiveness at the cost of some verbosity and extra types.
Those types should probably only exist to pass argument explicitly though IMO.
Transposing Rectangle would swap height and width.
Do you want to express a type? (as Length)
Extra types allow to be safer, at the cost of extra types, and possibly some "duplicated" functions (Length should be addable, (their product give Area), but adding Weight is also possible, duplicating the addition of their underlying type).
As const, Type might need to be propagated across the code.
Both?
You can :-)
As the concept are orthogonal. Instead of having a Height wrapping a int/double, it wraps a Length.
Let's for a moment ignore the point whether it is valid or not.
With an enum you might improve - even if I personally won't agree with that - the readability from the calling side.
But from the perspective of the code related to the Widget code itself those enum look wrong and confusing if those actually represent an integral with arbitrary values.
And if the values of complexity and size are limited to a certain range it might be a better idea to define a dedicated type for those.
If you want to go into a direction like your enum example I would use using instead.
using ComplexityInt = int;
using SizeInt = int;
template<ComplexityInt complexity>
class Widget
{
public:
Widget(SizeInt size);
};
int main()
{
Widget<ComplexityInt(4)> widget( SizeInt(12) );
return 0;
}
I believe those casts are undefined behavior, because those integers are outside the range of the enumeration values. From C++20 draft [expr.static.cast]/10:
If the enumeration type does not have a fixed underlying
type, the value is unchanged if the original value is within the range of the enumeration values (9.7.1), and
otherwise, the behavior is undefined.
I disagree that the code is unreadable without those casts. I think you're overthinking it.
With any decent editor, hovering over the class name (or ctrl-clicking to navigate to its definition) would show the definition along with the name of the complexity parameter. Same for the constructor and its size parameter.
Doing any of this casting weirdness would cause the reader to wonder what is going on, instead of just going on reading the code.
As others have already pointed out, casting is a type safety violation and should be avoided wherever possible, especially c style casts (the syntax (xxx) or xxx() is not important) because you haven't control of what the compiler is actually doing. Arguments decoration is not a valid reason to bypass the type safety of the language.
Well, aside this:
Widget</*Complexity*/ 4> widget(/*Size*/ 12);
If you want some compiler support, for the int argument you could safely do this:
struct Size
{
constexpr explicit Size(const int v) noexcept : value(v) {}
constexpr operator int() const noexcept { return value; }
int value;
};
template<int complexity>
class Widget
{
public:
Widget(Size size) {}
};
int main()
{
//Widget<4> widget(12); // Error: 12 is not a Size
Widget<4> widget(Size{12}); // Ok
}
The code is self explaining and I'm quite sure that this won't add overhead, the binary output will be the same.
Regarding the template argument the thing is a little more delicate.
Supposing that you have a finite number of possible complexities, you could do this:
enum class Complexity { min=1, mid, max, super };
template<Complexity complexity>
class Widget
{
public:
Widget(Size size) {}
};
int main()
{
//Widget<4> widget(Size{12}); // Error, 4 is not a Complexity
Widget<Complexity::super> widget(Size{12}); // Ok
}

Switching between two typedef structs, depending on boolean

I have a class with different functions. This class uses two typedef structs.
typedef struct {
struct head;
struct data1;
} data_struct_1;
typedef struct {
struct head;
struct data2;
} data_struct_2;
If a bool is true the data_struct_2 should be used, otherwise data_struct_1. The boolean is passed, when the object is created and stored as a membervariable in the constructor.
There are now different functions and declarations like
int calc_mean(data_struct_1 ds, int a){ ... }
or
data_struct_1 ds;
ds.data1 = 5;
Is there an elegant way, which allows me to switch between those two structs without implementing dozens of if-cases and duplicate all the relevant functions with the corresponding struct in the header?
First I was thinking about inheritance and overwritting relevant functions if bool is true.. but the header in the functions differs, so this wouldnt work
Maybe there is something like a placeholder or template, but i'm pretty new to c++
If boolean is compile-time value, std::conditional might be used:
template <boolean B>
using my_type = std::conditional_t<B, data_struct_1, data_struct_2>;
but it seems the boolean is runtime value, so I would use std::variant and std::visit:
class C
{
using Data = std::variant<data_struct_1, data_struct_2>;
Data m_data;
public:
C(bool b) : m_data{b ? Data{data_struct_1{}} : Data{data_struct_2{}}} {}
auto mean() const {
return std::visit([](const auto& data){ return calc_mean(data, 42); }, m_data);
}
};
You have a couple of options:
If the types are conceptually the same type of thing (i.e. they have the same interface and could be substituted for one another), you can:
Create an abstract base type and use polymorphism to change which concrete type is instantiated
Change all places that use these types into templates, change which template(s) are instantiated at runtime, and then rely on compile-time "duck-typing" to do the rest
If the types are conceptually different (i.e. they should not have the same interface), you can use a union type (union, std::variant).
Take a look at std::variant.
A variant can hold a number of alternative types, like this:
std::variant<data_struct_1, data_struct_2> m;
The member m can contain either a data_struct_1 or a data_struct_2. The variant will remember which, so there's no need for you to carry that bool around anymore.
The interesting question is now, how do you treat m in your functions? After all, it could be either a data_struct_1 or a data_struct_2 in there. Instead of using branches for distinguishing these cases, variant uses visit: Whenever you encounter a point in the function that depends on the concrete type stored in m, you move that code into two overloaded functions: One function that handles the data_struct_1 case and another that handles the data_struct_2 case. The example on the visit cppreference page shows some possibilities for doing that with varying degrees of syntactic overhead.
The good thing about this approach is that it forces you to always handle both cases properly. You can't just go ahead and write an implementation for one case and then forget about the other, having it blow up later at runtime. It also encourages a style where you clearly separate common parts of your code from type-specific parts, which often results in a cleaner design in the long term.
One possibility is to use std::variant:
typedef std::variant<data_struct_1, data_struct_2> data_struct_1_or_2;
void foo(data_struct_1_or_2 ds) {
if (auto ds1 = std::get_if<data_struct_1>(&ds)) {
// use ds1, which is type data_struct_1*
} else if (auto ds2 = std::get_if<data_struct_2>(&ds)) {
// use d2, which is type data_struct_2*
} else {
throw std::logic_error("Unexpected value in variant");
}
}
void bar(data_struct_1_or_2 ds) {
foo(ds); // Don't need to use an if statement here
}
If you have a data_struct_1 or data_struct_2 and want to pass a reference to the object, rather than a copy, you could use pointers in the std::variant instead (although it'll get a bit confusing with std::get_if because you'll end up with a pointer to a pointer):
typedef std::variant<data_struct_1*, data_struct_2*> data_struct_1_or_2_ptr;
A simple C solution would be a union with a bool tag:
typedef struct {
struct head;
bool type_flag;
union{
struct data1 d1;
struct data2 d2
};
} data_struct;
std::variant is an overkill for this case IMO. Inheritance and runtime polymorphism is a waste of runtime and memory.
Regards,
FM.

C++ class function to get/set multiple members

Class classname
{
int member1;
int member2;
...
int membern;
public:
void setmember1(int);
void setmember2(int);
...
void setmembern(int);
void getmember1(int);
void getmember2(int);
...
void getmembern(int);
}
I know that I can define 2n class functions to get and set n specified member values in-place for the declarations above.
However, this seems needlessly tedious when n is large. Is there a good way to define one class function that takes an extra argument to set/get any member of the class?
EDIT:
Syntax errors aside, my rationale for large n is to preserve the scientific framework behind the class. For example, say the class is enzyme. So I'd prefer to keep its properties in the same place and not index by number unless absolutely necessary.
Set/get functions are public because they're called in a different class (that sets up a GUI).
And, no, not all the members are ints. I copy-pastaed for the sake of simplicity.
In real code you should not have classes with many data members, and certainly not individually settable and gettable ones.
You could achieve what you are asking for using an array:
class classname
{
public:
setMemberDangerously(size_t index, int value) { data[index] = value; }
setMember(size_t index, int value)
{
if (! index < size) throw std::out_of_range("Index out of bounds");
data[index] = value;
}
private:
int data[N];
};
But now your class looks like a collection, in which case you might as well use a standard library container.
Either:
Write a script to generate the methods
Put all those integers into an array and use one get/set with an index
EDIT
Besides your get should be
int getX() const;
EDIT
Thought of another two possibilities
Overload the [] operator
Inherit from std::vector
You can invent any tools to make your bad-designed classes "almost manageable". If it's hard to write getters/setters, don't do this. Your class must be refactored.
General solution here is to avoid big values of n
Design your classes to preserve single responsibility principle. Avoid god-classes.
I am no fun of setters/getters, although they are quite common in applications like a GUI. Anyhow, I have a generic solution that does require a library and is probably an overkill for this problem. Assume you have the following class
class A
{
char member1;
int member2;
double membern;
public:
void set_member1(char c) { member1 = c; }
void set_member2(int i) { member2 = i; }
void set_membern(double d) { membern = d; }
char get_member1() { return member1; }
int get_member2() { return member2; }
double get_membern() { return membern; }
};
You can then write
auto val = _('c', 42, 3.14);
auto set = _(&A::set_member1, &A::set_member2, &A::set_membern);
auto get = _(&A::get_member1, &A::get_member2, &A::get_membern);
A a;
(a ->* set)(val);
cout << (a ->* get)() << endl;
which prints
(c, 42, 3.14)
That is, you are working with tuples. Syntax _(...) represents a tuple; val is a tuple of values (possibly of different types) and set/get are tuples of pointers to members. Operator ->* in the syntax given above allows calling multiple member functions on a single object with multiple arguments, one argument per function. The result of the call to get is again a tuple of values.
For all this to work, you need library ivl that I am currently developing. The syntax above is just a small sample; the library is much more flexible, allowing to define functions or operators for scalars and then call them on tuples or arrays, in any combination. All C++ operators are overloaded to allow this kind of "vectorization". Operator ->* can also work with function objects apart from pointers to members, so that calls are inlined. It also allows the alternative syntax
a ->* set._(val);
cout << a ->* get._() << endl;
so that member functions bind with arguments first, before being applied to the object(s). Member functions can have as many arguments (of any type) as you like, but all should have the same number of arguments in a single call.
You touched an old problem with C++, which is very limited reflection functionality in the language. The discussion below is worth to look at in case you came from a language with reflection:
How can I add reflection to a C++ application?
As for a practical advice, all other answers given here make perfect sense.

Static const integer class member in header-only file - the proper way?

Say I have the following example:
#include <cstdlib>
class A {
public:
static const std::size_t value = 42;
};
In short, I have (or better, want) a class A with a static const std::size_t member called value with the value 42 (determined at compile time).
Now, IIRC, this only works fine under certain circumstances. It doesn't, for example, when you take the address of A::value. In order for this to work fine in all cases you'd need to add a definition in some implementation file:
const std::size_t A::value;
However, I can't do this, because I want this file to be header-only. Another common solution is this:
class A {
public:
enum { value = 42 };
};
I don't like this solution either, because I'd like the type of A::value to be std::size_t.
What is a good solution to this problem? Preferably a small and portable solution, not something with huge macro magic like BOOST_STATIC_CONSTANT.
I'd like a solution for C++03, not C++11 (it's trivial there).
First of all, using the unsigned size_t type for numbers, you're likely to run into implicit promotion problems. So, good idea to use its corresponding signed type, which is called ptrdiff_t. Which, as it happens, is the result type of a pointer difference expression.
Also, due to changes in C++11, it’s generally a good idea to include <stddef.h> and not <cstddef>, i.e., write ::ptrdiff_t or just plain ptrdiff_t, not std::ptrdiff_t.
Now, here's how to do the header file extern linkage constant thing:
template< class Dummy >
struct A_constants_
{
static ::ptrdiff_t const value;
};
template< class Dummy >
::ptrdiff_t const A_constants_<Dummy>::value = 42;
typedef A_constants_<void> A_constants;
class A
: public A_constants
{
public:
// Whatever
};
Then you can use it like this:
foo( A::value );
There are also some other ways of doing this, but the above is about the simplest and easiest to get right.

Templated operator[]... possible? Useful?

Could you have:
template <class T>
const T &operator[] (unsigned int x)
My thinking was if you have a map<string,string> it would be nice to have a wrapper class which lets you do:
obj["IntVal"]="12";
obj["StringVal"]="Test";
int i = obj["IntVal"];
How close to this can we actually get in C++? Is it worth the pain?
You can also do
class Class {
struct Proxy {
template<typename T> T as() { ... }
template<typename T> operator T() { return as<T>(); }
private:
Proxy(...) { ... }
Proxy(Proxy const&); // noncopyable
Proxy &operator=(Proxy const&);
friend class Class;
};
public:
Proxy operator[](std::string const& s) { ... }
};
Class a;
int i = a["foo"];
int i = a["foo"].as<int>();
T will be deduced to whatever the to be initialized object is. And you are not allowed to copy the proxy. That said, i prefer an explicit as<T> function like another one proposed too.
You can't - in:
int i = obj["IntVal"];
the actual type of T can't be inferred from the context since the return type isn't part of the function signature.
Moreover, storing integer values as strings is not considered as best practices, due to memory and performance considerations ;-)
Not worth it.
Templating the return type means you'd have to explicitly specify the template parameter when you call it. Something like this, maybe I have the syntax wrong:
int i = obj.operator[]<int>("IntVal");
C++ does not deduce template parameters from what you assign the result of the call to, only from the parameters you call the function with.
So you might as well just define a normal function:
int i = obj.get<int>("IntVal");
Or in this case, either do this or implement get using this:
int i = boost:lexical_cast<int>(obj["IntVal"]);
As Amit says, you could define operator[] to return a type which can be converted either to int or to other types. Then your example code can be made to compile without the explicit lexical_cast.
Have you looked at boost variant? Is this what you're looking for?
Well, what you wrote in your sample code doesn't match the question. Right now, you only have the return type templated.
But if you wanted to do something like:
template <class T>
const T &operator[const T& x]
that's valid, though maybe not terribly useful.
A map already provides an overloaded operator[] that does most of what you want. The thing you seem to want that's missing is implicit conversion from a string that happens to contain digits to an integer. One of the fundamental characteristics of C++ is static typing, which says that shouldn't be allowed -- so it's not. It'll be happy to do that conversion if you want, but you'll have to ask for it:
int i = lexical_cast<int>(obj["IntVal"]);
Alternatively, you could create a string-like class that supported implicit conversion to int. Personally, I'd advise against that. I don't object to implicit conversions nearly as strongly as many people do, but that still strikes me as a pretty lousy idea, at least for most general use.