How do you create type copies? For example, how do I create types Mass, Acceleration and Force which are not implicitly convertible to double(or any other numeric type), but otherwise have all the characteristics of a double. This would allow a compile-time input validity check for this function:
Force GetForceNeeded(Mass m, Acceleration a);
ensuring that GetForceNeeded can only be called with arguments of type Mass and Acceleration.
Of course, I could achieve this by manually creating a copy of the type:
class Force final
{
public:
//overload all operators
private:
double value;
};
but this is cumbersome. Is there a generic solution?
As many commentators have pointed out, one solution is to use BOOST_STRONG_TYPEDEF which provides all the features requested in the question. And here's example usage from their docs:
#include <boost/serialization/strong_typedef.hpp>
BOOST_STRONG_TYPEDEF(int, a)
void f(int x); // (1) function to handle simple integers
void f(a x); // (2) special function to handle integers of type a
int main(){
int x = 1;
a y;
y = x; // other operations permitted as a is converted as necessary
f(x); // chooses (1)
f(y); // chooses (2)
} typedef int a;
There is a proposal to add opaque typedefs to C++1y.
(I am leaving this answer as I can't find an exact dupe. Please flag if that isn't the case.)
Related
I have been looking through source code trying to learn more about C++ and I came across some code that looked confusing. I haven't been able to figure out its use by playing around with it.
Please can someone explain what the operator float *() does and how it is used?
class Vector
{
public:
float x,y,z;
Vector() : x(0), y(0), z(0){
}
Vector( float x, float y, float z ) : x(x), y(y), z(z){
}
operator float*(){
return &x;
}
operator const float *(){
return &x;
}
I have searched StackOverflow and it looks like it is a conversion operator but I am still unsure what it actually does and why it is useful.
Kind regards,
operator type_name declares an implicit conversion operator. In other words, this function is called when you are attempting to (implicitly) convert an object of your type to float* – for instance in an assignment:
Vector x(1, 2, 3);
float* f = x;
assert(*f == 1);
Needless to say, this particular conversion is quite terrible because its effect is pretty unintuitive and easily results in impossible to find bugs. Implicit conversions should generally be handled with care since they hide potentially confusing semantics. But they can be used well with types which are supposed to be used interchangeably, and where a conversion doesn’t hurt.
For instance, consider the case where you write your own integer and complex classes. A conversion from integer to complex is harmless, since every integer is a complex number (but not vice-versa). So having an implicit conversion integer → complex is safe.
As it was said it is a conversion operator that converts an object of type Vector to an object of type float *. This conversion operator can be called implicitly because it has no function specifier explicit.
I think that the idea of introducing this operator was to access data members x, y, z as an array of floats. In this case you could apply some standard algorithms to an object of the class converting it to an array of floats.
Take into account that the second overloaded operator-function shall have qualifier const.
Consider the following code
#include <iostream>
#include <algorithm>
class Vector
{
public:
float x,y,z;
Vector() : x(0), y(0), z(0){
}
Vector( float x, float y, float z ) : x(x), y(y), z(z){
}
operator float*(){
return &x;
}
operator const float *() const {
return &x;
}
};
int main()
{
Vector v( 1, 3, 2 );
auto max = std::max_element( v + 0, v + 3 );
std::cout << *max << std::endl;
return 0;
}
The output is 3.
Take into account that according to the C++ Standard
13 Nonstatic data members of a (non-union) class with the same access
control (Clause 11) are allocated so that later members have higher
addresses within a class object
So the order of the data members of the class is defined.
It's a conversion operator allowing the class to be used with APIs that want a float*.You have two different versions because one will convert the class to a const float* and the other to a non-const. The non-const conversion operator breaks your class's encapsulation though.
Usefulness: Well it can be very handy when, as I mentioned, you want to work with a library that expects a certain type. It can also be useful when there is a natural conversion between two types.
PI'm trying to wrap float, int, etc primitves value into my SParam class. But I have some problem with getting values from this struct. I want to use this struct as I use for example floats.
template<class T>
struct SParam
{
T value;
SParam()
{
}
operator T() const
{
return value;
}
};
SParam<float> a;
a.value = 4;
printf("%f", a); //<--this don't print a.value
The problem with using the "naked" SParam<float> a with printf (or any other function that takes a variable number of arguments, for that matter) is that the compiler does not know that you want to pass a float. That is why the type-specific conversion is not applied. If you call a function with a specific parameter type, say
void printFloat(float f) {
printf("%f", f);
}
...
SParam<float> a;
a.value = 4;
printFloat(a);
then the compiler would figure out from the signature of printFloat that your conversion to float needs to be applied, and everything would work as expected. Of course you can always apply the conversion manually:
printf("%f", (float)a);
Because you need to call a() in the printf, not a.
a is just an object of type SParam, you'll probably need to modify the operator definition to specify a return type of T as well..
for comparison try using float x = a; it should give you an error. float x = a(); should not however
I understand that the overloading a function is legal if the number of parameters are different, or if the parameter type is different.
Why is it that a difference of only the return type is not legal?
Also, is it legal to overload as such:
int hello(int x);
int hello(int &z);
also
int hi(int x);
int hi(int *z);
There's no way for the compiler to figure out which function you're trying to call by just the return value. Since a return value does not need to be caught, you could write:
hello( 1 ); // return int
hello( 2 ); // return float
They are exactly the same call from what can be seen.
Yes that is legal since the first hi takes a reference and the second hi takes a memory address. You might call it like this:
hi( myNumber );
hi( &myNumber );
Perfectly distinguishable.
It's hard for compiler to choose an overload based on the return type. In many situations there is no explicit statement for compiler to deduce the programmer's purposed return type. Even if it was possible, it's confusing for programmers.
Assume C++ has overloading based on return values:
float func() {...};
int func() {...};
int x = func(); // OK, compiler may choose `int` version!
BUT, How about...
cout << func() + func();
What do you expect? Maybe we can define some rules, but it will make codes complex, confusing and unreadable.
Other overloadings are legal. Due to different entry argument types.
You can't overload:
int hello(int x) // 1
{
return x;
}
int hello(int& x) // 2
{
return x;
}
int hello(int const& x) // 3
{
return x;
}
void foo()
{
int i = 10;
hello(i); // Can't disambiguate between 1 and 2
hello(10); // Can't disambiguate between 1 and 3
}
However, you can overload:
int hello(int& x) // 4
{
return x;
}
int hello(int const& x) // 5
{
return x;
}
void foo()
{
int i = 10;
hello(i); // Picks 4
hello(10); // Picks 5
}
Think about how the compiler might be able to figure out what function you want to be called. In the first example, if I write
int z = 5;
int y = hello (z);
How is the compiler going to figure out which function you want to be called? But in the second example,
int z = 5;
int y = hi (z);
int u = hi (&z);
it's clear which function to call. You can't overload on return type alone because the compiler needs the parameters to choose the function to call.
For me it's good, this is not the same type; for exemple int x is an integer, but int *z is un pointer of integer.
There are really no technical problems with allowing overloading on return type in many cases, the compiler knows what type is needed for the expression the function call is in and so knows which function to call. There are some problems though, for example if the returned value is not used, then you will have an ambiguity.
As for the functions, all of those are valid overloads. You might have some ambiguity in the case of hello depending on how you call it, for example if you call it with a variable then the compiler can't really tell which version of hello you want.
Since int, int& and int* are all different types then overloading on these is legal.
You can also overload on const which can be useful when designing classes which exhibit true const correctness.
int hello(int);
int hello(int) const;
You cannot overload on return types since the compiler would not know which function to use in full generality, especially if the function return type is discarded by the caller.
I was confused about why can't compare pointers to member using binary operator<
class Point3d{
protected:
//..
public:
float x;
static list<Point3d*> *freeList;
public:
float y;
static const int chunkSize = 250;
public:
float z;
};
and a template:
template< class class_type, class data_type1, class data_type2 >
char* access_order(data_type1 class_type:: *mem1, data_type2 class_type:: *mem2)
{
return
mem1 < mem2 ?
"member 1 accurs first":
"member 2 accurs first";
}
when I called the access_order like below:
access_order(&Point3d::z, &Point3d::y);
the g++ reported:
"invalid operands of types ‘float Point3d::*’ and ‘float Point3d::*’ to binary ‘operator<’"
Is there a way compare pointer to member, I mean the unequal comparison, and how?
You can compare the addresses of the members of an object:
A a;
if (std::less<void*>()(&a.a, &a.b))
std::cout << "a precedes b\n";
else
std::cout << "a follows b\n";
One of the best option - make a raw copy via std::memcpy, calculate hash and then use it for comparison (thanks #HolyBlackCat for comments). The function below calculates the hash for passed pointer-to-member (tested on modern C++ 17 compilers VS, GCC. CLang).
#include <cstring>
#include <string_view>
#include <functional>
template <typename TObject, typename TMember>
size_t HashMemberPtr(TMember TObject::* memberPtr)
{
char buf[sizeof memberPtr];
std::memcpy(&buf, &memberPtr, sizeof memberPtr);
return std::hash<std::string_view>{}(std::string_view(buf, sizeof buf));
}
Unfortunately it's not compatible with std::hash<> as last requires only one template argument.
How to use:
struct CPoint3D
{
float x;
float y;
float z;
};
int main()
{
const size_t xHash = HashMemberPtr(&CPoint3D::x);
assert(xHash == HashMemberPtr(&CPoint3D::x));
assert(xHash != HashMemberPtr(&CPoint3D::y));
assert(xHash != HashMemberPtr(&CPoint3D::z));
return 0;
}
For the same reason you can't compare pointers in general. The only
comparisons for order that are supported is if two data pointers point
into the same array. Otherwise, the results of the comparison are
unspecified; a compiler is not required to make the operators "work" in
any reasonable way. (Ensuring a total order here would require extra
computation on some architectures.) Since there's no case you can get
specified results for a pointer to member, the standard doesn't allow
them as arguments to the operators.
If you need total ordering, std::less et al. is guaranteed to provide
it. Including, if I understand the standard correctly, member pointers.
(Although providing a total ordering for pointer to member functions
would probably be very expensive.) Even then, however, this ordering
may be arbitrary; it would certainly not be required to reflect any
ordering in memory.
If the Point3d overloads < then deference them and do the compare,
return
*mem1 < *mem2 ?
"member 1 accurs first":
"member 2 accurs first";
or change the signature
char* access_order(data_type1 class_type:: &mem1, data_type2 class_type:: &mem2)
char* access_order(data_type1 class_type:: mem1, data_type2 class_type:: mem2)
Did you want to do the compare on the actual memory address?
Pointers to members do not point to some memory themselves. They are just labels. The only thing you can do with them is to convert them to reference to pointee value of the given object with operator .* or ->* or store in another pointer to member variable.
struct A
{
int a;
float b;
};
A a;
int A::* p2m = &A::a;
int A::* p2m2 = p2m;
int & realPointer = a.*p2m;
Note, that you only can compare pointers of the same type, so you can't compare pointer to A::a (int A::*) with pointer to A::b (float A::*)
Pointer comparison seem to tempting everyone but they always lead to a non-portable or undefined behavior.
The easiest answer is that you should never do this. There is no computational problem that cannot be solved with classical approaches.
Don't get me wrong, I am aware that asking wrong questions might get interesting thoughts, or a build better understanding on how a language or even CPU works.
I have just started C++ and have come across references and have not understood completely.
References , as i read is an alternative name for an object.Why use that instead of directly accessing the object as any operation on references is directly reflected on the object ...?
Why and when are they used ?
Is ist like a constant pointer that is referenced each time it is used ... ?
And , it says
double& dr = 1; ---- says it is an error (some lavalue needed)
const double& cdr = 1; ---- says it is ok.
i dont understand it properly..So please explain why it is so ...
Thank You...:)
Why use that instead of directly
accessing the object as any operation
on references is directly reflected on
the object ...?
C++ passes parameters by value, meaning if you have a function such as:
void foo(MyObject o) { ... }
By default C++ will make a copy of a MyObject, not directly use the object being passed in. So, one use of references is to ensure you are working on the same object:
void foo(MyObject &o) { ...}
Or, if you aren't modifying o:
void foo(const MyObject &o) { ... }
References are another way of what was originally in C code like this
void fubarSquare(int *x){
int y = *x;
*x = y * y;
}
// typical invocation
int z = 2;
fubarSquare(&z);
// now z is 4
with references in C++ it would be like this
void fubarSquareCpp(int& x){
x = x * x;
}
// typical invocation
int z = 2;
fubarSquareCpp(z);
// now z is 4
It's a neater syntactical way of using a call-by-reference parameter instead of using the C's notation asterisk/star to indicate a pointer and as a call-by-reference parameter...and modifying the parameter directly outside of the function...
Have a look at Bjarne Stoustrap's page here which covers how C++ is and also here on the technical faq here
A reference is basically a pointer that looks like an object. It is very very hard to get a NULL reference though you can go through hoops and create one.
With regards to your example, 1 is an rvalue or a result. It is just a temporary variable and can not be modified. Thus you can't take a non const reference to it. However you can take a const reference to it. This means you can't change the value of the reference.
Here is an example of creating a NULL reference. Don't do it!
int * x = (int *)NULL;
int & y = *x;
I agree with you. using references as just an alias name is not very useful.
It is more useful if you consider it as an immutable pointer. But not that useful in fact.
Practically, it is used to define clean interfaces. For example when you define:
int foo(const int& param);
You say that param is a read-only parameter in foo.
Do not forget that you MUST assign a value to a reference.
See the C++ faqlite on references for more
my2c
References improve the syntax, so no pointer dereference needed.
Assuming Base is a class that may be derived from:
void someFunction(Base b)
{
b.function();
// b is a copy of what was passed - probably performance issues
// possible unintended object slicing - you only get the Base part of it
// no virtual function call
// no changes to b visible outside the function
}
void someFunction(Base* b)
{
b->function();
// a shortcut for (*b).function();
// b is the same object that was passed to the function
// possible virtual call
// changes visible outside the function
}
void someFunction(Base& b)
{
b.function();
// b is the same object that was passed to the function
// possible virtual call
// changes visible outside the function
}
References are like constant pointers (NOT pointers to constants - i.e. you can change the object, but you can't change to what you're pointing). const reference is a reference through which you can do things that can be done on const object.
References are also good, because you can't have a null reference
Give the wikipedia article a good read through. To sum it up, references are more friendly version of pointers which are commonly used to pass objects as references into functions without worrying about a null pointer.
To explain the example:
Think of the number 1 represented as a variable. When compiled, this number is put into the global section of the memory which can be referenced by the program, but not modified.
So it is of type: const int
double &dr = 1 is trying to assign dr (a reference to a double) to the const int 1. Since 1 is a constant, the compiler will not allow you to make a non-constant reference to it.
In the second line:
const double &dr = 1 is trying to assign dr (a constant reference to a double) the const int 1. This works because the reference is also const and therefore can point to a const int.
EDIT
The const int is converted to a const double before assigned.
References are language entitities that represent another object they refer to. Nonconst references are lvalues, and must be initialized with an lvalue. They can be useful like this:
int& x=condition ? array[1] : array[2];
int& y=condition ? array[0] : array[3];
x+=y;
y=0;
When used as a function parameter, they tell the caller he has to pass an lvalue that might be written to by the function:
void set1(int& x) { x=1; }
int foo;
set1(foo); // ok, foo is 1
set1(foo+1); // not OK, not lvalue
Const references, on the other hand, can be bound to rvalues. In function parameters, they are usually used to avoid excessive copies:
void niceness(std::string s); // the string would be copied by its copy-ctor
void niceness(const std::string& s); // the caller's string would be used
Note that this may or may not yield faster code.
When const-references are used in normal code, they can bind rvalues, too, and as a special rule, they extend the lifetime of the object they are bound to. This is what you saw in your code:
const double& d=1; // OK, bind a rvalue to a const-ref
double& d=1; // Bad, need lvalue
All references are polymorphic, like pointers:
class A { virtual void f(); }
class B : public A { void f(); }
B b;
A& ar=b;
ar.f(); // calls B::f()
and all references are aliases like pointers:
int f(int& a, const int& b)
{
a=1;
return b;
}
int x;
f(x, 42); // ==42, foo=1
x=42;
f(x, x); // ==1 (not 42), foo=1
double& dr = 1; // 1.0 would be more clear
Is invalid because 1 is viewed to be of type const double so if you want a reference to that variable you need to have a reference to a const double so
const double& dr = 1.0;
Is correct.
Utility of references is most visible in the context of passing parameters to functions.
I.e,
int a;
func definition: void foo (int& param) {param = 1;}
func call: foo(a);
The way as 'param' aliases 'a' is clean and its intention is easily understood by a reader of this code as well as compiler that may optimize away when inlining any additional memory allocation needed for the reference.
Passing a reference to a function and then having the function use the reference is almost like passing a pointer to the function and then having the function dereference the pointer. In many cases, the machine-code implementation will be identical. There are some differences, though, especially in the case of functions that get expanded inline. If a variable is passed by reference to an inline function, the compiler will often be able to substitute the variable itself--even if stored in a machine register--when expanding the function. By contrast, if one takes the address of a variable and passes that as a pointer to a function which then dereferences it, the compiler is less likely to figure out that optimization unless it determines not only that--at least for one particular expansion of the function--the pointer will always point to that variable, but also that the pointer will not be used anywhere else (if the pointer was used elsewhere, the variable could not be kept in a register).