This is kinda like my earlier question:
C++: Vector3 type "wall"?
Except, now, I want to do this to a builtin rather then a user created type.
So I want a type "Length" that behaves just like float -- except I'm going to make it's constructor explicit, so I have to explicitly construct Length objects (rather than have random conversions flying around).
Basically, I'm going into the type-a-lot camp.
Like suggested in a comment over at your other question you can use units from boost. This should be explicit and still manageable.
It sounds like you want to wrap a float primitive in your own class. Here's an example to get you started:
class Length
{
protected:
float value_;
public:
Length(float value) : value_(value) { }
static Length operator +(Length a, Length b) { return Length(a.value_ + b.value_); }
static Length operator -(Length a, Length b) { return Length(a.value_ - b.value_); }
static Length operator *(Length a, Length b) { return Length(a.value_ * b.value_); }
static Length operator /(Length a, Length b) { return Length(a.value_ / b.value_); }
};
But, using the boost Units library is a much better choice in the long run...
Related
I had functions that were supposed to take an ID number (an int), but I noticed that I was accidentally passing the ID numbers of different things, which broke my program. So I tried to do something like the following to make it type-safe:
struct Number
{
int ID;
int operator =(const int& rhs) { ID = rhs; }
}
struct DogID : Number { }
struct CatID : Number { }
void functionTakingDogID(DogID ID) { }
void functionTakingCatID(CatID ID) { }
int main()
{
DogID dogID;
dogID = 5; // But the = operator overload isn't inherited
}
The only reason I created classes to hold the numbers was to prevent passing the wrong ID number. And the reason I used inheritance from Number is so that any classes like Dog and Cat could be treated like an ID number (assigned to).
What's the cleanest way to be able to send ID numbers to a function but ensure that you're sending the right IDs to it? I'm not sure enum classes are an option because IDs are given at runtime.
Also I found out that:
All overloaded operators except assignment (operator=) are inherited by derived classes.
Is the reason for why the operator = is the only operator overload not inherited that it was considered too risky given that derived classes may have extra members?
What you can do is to use a Tag for your Number
template<typename Tag>
struct Number
{
int ID;
Number &operator =(int rhs) { ID = rhs; return *this;}
};
using DogID = Number<struct DogIdTag>;
using CatID = Number<struct CatIdTag>;
int main()
{
DogID dogID;
dogID = 5; // But the = operator overload isn't inherited
}
The idea is to give a kind of tag to your Number class. Doing so will ensure that Number<Tag1> is not of the same type of Number<Tag2>
However, in a general architecture, I would not recommand using an operator= on int, because you lose a bit of type safety.
For example, in this code:
void f(int accountId) {DogId id = accountId;}
It is not that good and I recommand you to only use such a thing :
DogId id = DogId{anInteger}
and to continue to use the template Number class we saw above
Note
Your operator= function must return a reference on the current object, not a int.
It is dangerous to not return something from a function that need to return something. In C it is dangerous, In C++ it is an undefined behaviour.
I have a problem in C++ that is similar to this example problem. In this case I have two member-functions that have an identical interface. Based on the information in a string passed to the super function, I would like to assign one of the two member functions to the variable class_func. Is there a way to do this?
// test.hpp
class TestClass
{
public:
double master_function(double a, double b, std::string func_name);
private:
double add(double a, double b);
double subtract(double a, double b);
};
// test.cpp
double TestClass::master_function(double a, double b, std::string func_name)
{
if (func_name == std::string("Add") const auto& class_func = add;
else const auto& class_func = subtract;
return class_func(a, b);
}
// =========================================================================
double TestClass::add(double a, double b)
{
return a + b;
}
// =========================================================================
double TestClass::subtract(double a, double b)
{
return a - b;
}
In other words, I am trying to assign the member-function add or subtract to the name class_func, so the code underneath the if statement in master_function can be uniform regardless of which function the user wants to use. In the form shown below I get the error Reference to non-static member function must be called out, but I am not totally sure what this means or how to fix it. In addition, I am using a C++17 compiler, so if there is a modern approach that works best with C++17 I would be interested in learning it.
The term you are looking for is member function pointer, but we can do without explicitly specifying that type. The problem with your code is not only in the way you try to refer to a member function (that would be &TestClass::add), but also that you create those aliases in a nested scope (under if/else), meaning they won't be visible in the return statement.
The simplest change is this:
auto class_func = &TestClass::add; // pick one default
if (func_name == "Subtract")
{
class_func = &TestClass::subtract;
}
else
{
assert(func_name == "Add"); // optional
}
return class_func(a, b);
This works because the add and subtract functions have the exact same type:
double (TestClass::*)(double a, double b)
But yeah, why are those functions not static? They do not work with a class' instance. Make them static and the above will still work, just note that the type of class_fun will be a simple function pointer:
double (*)(double a, double b)
Now that you know the types, you could change this in a way that does not privilege one function before the other in the code:
decltype(&TestClass::add) class_func = nullptr;
if (func_name == "Add")
{
class_func = &TestClass::add;
}
else if (func_name == "Subtract")
{
class_func = &TestClass::subtract;
}
assert(class_func != nullptr);
return class_func(a, b);
As mentioned in the comments, as that if-else chain starts to get longer, it makes more and more sense to use a (hash)map between strings and function pointers.
How to design a type that can take an expression in the form of an algebraic expression with numbers and units, where Speed is the type, 23m / 10s could be an expression?
Example:
change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second
EDIT This question raised the question if a literal in the form of 23m is possible at all.
EDIT the reference to the source has been removed from question for clarity. It can be found here
What you have to do is design types that when the expression is evaluated it yields the desired type. With
change_speed(23m / 10s);
We need 23m and 10s to each yield a type that when you divide them together gives you a Speed. If we have a
struct Meter
{
Meter(double value) : value(value) {}
double value;
};
struct Second
{
Second(double value) : value(value) {}
double value;
}
Speeds operator /(const Meter& m, const Second& s)
{
return Speed(m.value / s.value);
}
Then we just need to define literal operators for Meter and Second like
Meter operator "" _m(double value) { return Meter(value); }
Second operator "" _s(double value) { return Second(value); }
we have to use _m and _s to make these valid user defined literals. All literals besides those provided by the standard must start with a _.
Then
change_speed(23_m / 10_s)
becomes
change_speed(Meter(23) / Second(10))
which becomes
change_speed(Speed(2.3))
It sounds like you want something like a units/dimensional analysis type system. See for example Boost.Units.
The fundamental (length, time, etc.) units are defined similarly to the duration types in std::chrono - just with more than one (time) distinct dimension. The arithmetic operators are implemented to combine units into correctly-dimensioned compound types.
So, rather than defining Speed as an independent type, it's derived from the fundamental Metre and Second types (which are themselves instances of the length and time units, which are probably instances of a generic unit template differentiated by tag types).
If you want to write user-defined literals for SI units, there are examples on codeproject or in this project on Github - I haven't read through either and can't vouch for their quality, but the idea is fine.
From reading the section of the CPPCoreGuidelines I think that maybe you are confusing the intent of the section. The main point is:
Express ideas directly in code.
The concept being that the code change_speed(double s) is ambiguous because the units and identity of type is ambiguous. Furthermore change_speed(double speed_m_p_s) is no good because it is easy to get wrong. The suggestion is therefore that you explicitly create the input type. Something like:
enum class SpeedType {
M_p_S
Km_p_H
...
}
template<SpeedType type>
class Speed {
explicit Speed(double speed)
... // Some fully specified class that represents a speed.
template<SpeedType type>
void change_speed(Speed<type> s) { ...
change_speed(2.3) // Implicit conversion means this will be an error
change_speed(Speed<M_p_S>(2.3)) // It is clear to the reader and compiler that this is of type speed
// with unit of M_p_S. Go to the Speed class for more information.
This is not a perfect example. But conceptually, this is what they are trying to inform you with this section.
If I've understood the question correctly.
For required behaviour you can use next c++ features.
1) We're need class describes time. There are need classes in STL.
std::chrono::seconds, std::chrono::minutes and other. For literals using you must add:
#include <chrono>
using namespace std::chrono_literals;
auto thetime = 10m; // it's okey. the time have type std::chrono::minutes
2) We're need class describes distances. There aren't distance classes in STL.
3) We're need class speed.
4) We're need division operator for distance and time argument.
class distance
{
public:
inline constexpr distance(
const unsigned long long millimeters) :
millimeters_{ millimeters }
{
}
inline long double millimeters() const noexcept
{
return (millimeters_);
}
inline long double santimeters() const noexcept
{
return (millimeters_ / 10);
}
inline long double meters() const noexcept
{
return (millimeters_ / 1000);
}
inline long double kilometers() const noexcept
{
return (millimeters_ / 1000000);
}
private:
long double millimeters_; // it's must be least dimension unit
};
inline constexpr distance operator""_mm(const unsigned long long value)
{
return distance{ value };
}
inline constexpr distance operator""_cm(const unsigned long long value)
{
return distance{ value * 10 };
}
inline constexpr distance operator""_m(const unsigned long long value)
{
return distance{ value * 1000 };
}
inline constexpr distance operator""_km(const unsigned long long value)
{
return distance{ value * 1000000 };
}
// !
// it's need the same operators"" only for long long argument types
// !
class speed
{
public:
// ...
speed(long double)
{
}
// ...
};
template <typename _Rep>
speed operator/(
const distance& the_distance,
const std::chrono::duration<_Rep>& the_time)
{
// divide by zero!
return speed{ the_distance / the_time };
}
void speed_test(const speed&)
{
}
void foo()
{
using namespace std::chrono_literals;
speed_test(100_km / 21s);
}
In a function that takes several arguments of the same type, how can we guarantee that the caller doesn't mess up the ordering?
For example
void allocate_things(int num_buffers, int pages_per_buffer, int default_value ...
and later
// uhmm.. lets see which was which uhh..
allocate_things(40,22,80,...
A typical solution is to put the parameters in a structure, with named fields.
AllocateParams p;
p.num_buffers = 1;
p.pages_per_buffer = 10;
p.default_value = 93;
allocate_things(p);
You don't have to use fields, of course. You can use member functions or whatever you like.
If you have a C++11 compiler, you could use user-defined literals in combination with user-defined types. Here is a naive approach:
struct num_buffers_t {
constexpr num_buffers_t(int n) : n(n) {} // constexpr constructor requires C++14
int n;
};
struct pages_per_buffer_t {
constexpr pages_per_buffer_t(int n) : n(n) {}
int n;
};
constexpr num_buffers_t operator"" _buffers(unsigned long long int n) {
return num_buffers_t(n);
}
constexpr pages_per_buffer_t operator"" _pages_per_buffer(unsigned long long int n) {
return pages_per_buffer_t(n);
}
void allocate_things(num_buffers_t num_buffers, pages_per_buffer_t pages_per_buffer) {
// do stuff...
}
template <typename S, typename T>
void allocate_things(S, T) = delete; // forbid calling with other types, eg. integer literals
int main() {
// now we see which is which ...
allocate_things(40_buffers, 22_pages_per_buffer);
// the following does not compile (see the 'deleted' function):
// allocate_things(40, 22);
// allocate_things(40, 22_pages_per_buffer);
// allocate_things(22_pages_per_buffer, 40_buffers);
}
Two good answers so far, one more: another approach would be to try leverage the type system wherever possible, and to create strong typedefs. For instance, using boost strong typedef (http://www.boost.org/doc/libs/1_61_0/libs/serialization/doc/strong_typedef.html).
BOOST_STRONG_TYPEDEF(int , num_buffers);
BOOST_STRONG_TYPEDEF(int , num_pages);
void func(num_buffers b, num_pages p);
Calling func with arguments in the wrong order would now be a compile error.
A couple of notes on this. First, boost's strong typedef is rather dated in its approach; you can do much nicer things with variadic CRTP and avoid macros completely. Second, obviously this introduces some overhead as you often have to explicitly convert. So generally you don't want to overuse it. It's really nice for things that come up over and over again in your library. Not so good for things that come up as a one off. So for instance, if you are writing a GPS library, you should have a strong double typedef for distances in metres, a strong int64 typedef for time past epoch in nanoseconds, and so on.
(Note: post was originally tagged 'C`)
C99 onwards allows an extension to #Dietrich Epp idea: compound literal
struct things {
int num_buffers;
int pages_per_buffer;
int default_value
};
allocate_things(struct things);
// Use a compound literal
allocate_things((struct things){.default_value=80, .num_buffers=40, .pages_per_buffer=22});
Could even pass the address of the structure.
allocate_things(struct things *);
// Use a compound literal
allocate_things(&((struct things){.default_value=80,.num_buffers=40,.pages_per_buffer=22}));
You can't. That's why it is recommended to have as few function arguments as possible.
In your example you could have separate functions like set_num_buffers(int num_buffers), set_pages_per_buffer(int pages_per_buffer) etc.
You probably have noticed yourself that allocate_things is not a good name because it doesn't express what the function is actually doing. Especially I would not expect it to set a default value.
Just for completeness, you could use named arguments, when your call becomes.
void allocate_things(num_buffers=20, pages_per_buffer=40, default_value=20);
// or equivalently
void allocate_things(pages_per_buffer=40, default_value=20, num_buffers=20);
However, with the current C++ this requires quite a bit of code to be implemented (in the header file declaring allocate_things(), which must also declare appropriate external objects num_buffers etc providing operator= which return a unique suitable object).
---------- working example (for sergej)
#include <iostream>
struct a_t { int x=0; a_t(int i): x(i){} };
struct b_t { int x=0; b_t(int i): x(i){} };
struct c_t { int x=0; c_t(int i): x(i){} };
// implement using all possible permutations of the arguments.
// for many more argumentes better use a varidadic template.
void func(a_t a, b_t b, c_t c)
{ std::cout<<"a="<<a.x<<" b="<<b.x<<" c="<<c.x<<std::endl; }
inline void func(b_t b, c_t c, a_t a) { func(a,b,c); }
inline void func(c_t c, a_t a, b_t b) { func(a,b,c); }
inline void func(a_t a, c_t c, b_t b) { func(a,b,c); }
inline void func(c_t c, b_t b, a_t a) { func(a,b,c); }
inline void func(b_t b, a_t a, c_t c) { func(a,b,c); }
struct make_a { a_t operator=(int i) { return {i}; } } a;
struct make_b { b_t operator=(int i) { return {i}; } } b;
struct make_c { c_t operator=(int i) { return {i}; } } c;
int main()
{
func(b=2, c=10, a=42);
}
Are you really going to try to QA all the combinations of arbitrary integers? And throw in all the checks for negative/zero values etc?
Just create two enum types for minimum, medium and maximum number of buffers, and small medium and large buffer sizes. Then let the compiler do the work and let your QA folks take an afternoon off:
allocate_things(MINIMUM_BUFFER_CONFIGURATION, LARGE_BUFFER_SIZE, 42);
Then you only have to test a limited number of combinations and you'll have 100% coverage. The people working on your code 5 years from now will only need to know what they want to achieve and not have to guess the numbers they might need or which values have actually been tested in the field.
It does make the code slightly harder to extend, but it sounds like the parameters are for low-level performance tuning, so twiddling the values should not be perceived as cheap/trivial/not needing thorough testing. A code review of a change from
allocate_something(25, 25, 25);
...to
allocate_something(30, 80, 42);
...will likely get just a shrug/blown off, but a code review of a new enum value EXTRA_LARGE_BUFFERS will likely trigger all the right discussions about memory use, documentation, performance testing etc.
this is for an assignment so I will be deliberately general. My question is related to implementation decisions I already made--maybe they weren't good ones.
I have a list of pointers to structs, e.g. list<MyStruct*> bob; At one point I've needed to sort these pointers by one of the data members of their targets and I was able to do that easily with
bool sortbyarrival(const MyStruct* a, const MyStruct* b) {
return a->arrival < b->arrival;
}
And then calling bob.sort(sortbyarrival); Works great.
Now somewhere else I need to sort by a different criterion, which involves a counter in the program. I need something like return counter*a->arrival < counter*b->arrival; But the way I just described is the only way I know how to do a sort, I think, and I don't know how to pass my counter as an additional argument. How can I sort this list of pointers?
ETA: The counter is just a variable in main. So ideally I could call something like bob.sort(sortbyratio, counter); or sort(bob.begin(), bob.end(), sortbyratio, counter);
Similar to ltcmelo's example, but if the objects themselves don't contain the counter:
struct sort_with_counter {
sort_with_counter(const double d): counter(d) {}
bool operator()(const MyStruct* a, const MyStruct* b) {
return(counter*a->arrival < counter*b->arrival);
}
const double counter;
};
mylist.sort(sort_with_counter(5.0));
If your counter is an external variable like that though it won't affect the ordering (at least if it's positive - thanks onebyone!) - so this may in fact not be necessary at all (or maybe I misunderstand what you're after?). It's a useful technique in other cases though.
Create a functor, and store the extra value in the functor object:
struct CompareByCounter {
CompareByCounter(int c) : counter(c) {}
bool operator()(const MyStruct *lhs, const MyStruct *rhs) {
return (counter * lhs->arrival) < (counter * rhs->arrival);
}
private:
int counter;
};
// sort ascending
bob.sort(CompareByCounter(1));
// sort descending
bob.sort(CompareByCounter(-1));
Just create an function-object, a class/struct with an overload of operator() that does the right thing for you. In this case, taking into consideration the extra variables. Then, you pass an instance of it to the sort method.
struct my_comparison : binary_function<MyStruct const*, MyStruct const*, bool>
{
bool operator()(MyStruct const* a, MyStruct const* b)
{
return (a->counter * a->arrival) < (b->counter * b->arrival);
}
};
//Use it this way.
my_comparison comp;
//Set the arrival and counter data in instance comp.
/* ... */
//Now, pass it to the list.
bob.sort(comp);
EDIT: I just noticed that you have a list of pointers so I changed a bit the struct.