compare a pointer to member? - c++

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.

Related

Using variables versus pointers to variables as parameters for a function

When a function requires a pointer as an argument (and not the variable that the pointer references), is this simply because of the size of the values that would be passed to the function?
I can understand how someone would want to pass a pointer to an array or struct, rather than passing the entire array or struct, but are their other reasons for this decision? For example, a function requiring a pointer to an int (4 bytes) rather than the int (4 bytes) itself.
If you would like your function to change the value of a parameter (such as an int), then you must pass in a pointer to it. Otherwise, any changes that your function makes will be made on a copy.
In general, so-called "output parameters" in C and C++ are often pointers to whatever variable is to be affected by the function.
As for arrays, C doesn't actually permit one to pass a large block of memory to a function, and so we have no choice but to pass a pointer.
(Edit: as discussed in the comments, this answer applies to pointers only. In C++, one may also use references)
In C++ you would pass built in types by value except when you want to modify them in the method or function and have the modification apply to the original variable.
You can pass by reference or by pointer. Some people prefer to pass by pointer if they are going to modify the input as it is more explicit as you have to dereference the pointer.
IE:
void foo(int& a, int* b)
{
a = 1; // This modifies the external variable, but you can't see that just looking at this line
*b = 1; //explicitly modifying external variable
}
int z = 0;
int y = 0;
foo(y, &z); //z is explicitly being allowed to be modified, that y can be too isn't apparent until you look at the function declaration.
Others think this passing pointers is ugly and don't like it.
The best practice for passing large types around is by const reference, which says you won't be modifying the instance.
The answer in one line is: pass-by-(pointer/reference)-to-const if you are dealing with input parameters to non fundamental types, pass-by-value if you are dealing with input parameters to fundamental types, pass-by-(pointer/reference) otherwise. As pointed out in the comments (thanks TonyD) this last "rule" is meant to be an optimisation over using pass-by-(pointer/reference)-to-const; it is likely unnecessary, but it's worth nowing. Note that passing by reference to const does not inficiate the ability to call a function with a temporary (be it a literal or a result from a function call) parameter.
Several distinctions have to made to answer this question appropriately. First of all C and C++ are two different beasts: the only options in C are pass-by-value (pbv), pass-by-pointer (pbp) and pass-by-pointer-to-const (pbptc). In C++ you have also the option to pass-by-reference (pbr) and pass-by-reference-to-const (pbrtc). Secondly, there is the distinction between an input parameter and an (input/)output parameter; when a parameter belongs to the second class you have no options but pbp or pbr (if appliable, i.e. if using c++). As for input parameters, the considerations to be made are more subtle. Alexandrescu addresses this issue in his book "Modern C++"
you sometimes need to answer the following question: Given an
arbitrary type T, what is the most efficient way of passing and
accepting objects of type T as arguments to functions? In general, the
most efficient way is to pass elaborate types by reference and scalar
types by value. (Scalar types consist of the arithmetic types
described earlier as well as enums, pointers, and pointers to
members.) For elaborate types you avoid the overhead of an extra
temporary (constructor-plus-destructor calls), and for scalar types
you avoid the overhead of the indirection resulting from the
reference.
(of course, for input parameters, he is referring to pbrtc). Similarly, you should choose to pbptc for "elaborate" types in C.
Finally, if you are using C++, you can automate this choice by using "type traits" (either the standard ones or custom written ones, see Modern C++ for more on this). Type traits allow you to automatically know if a type is a fundamental type, if it is a reference already (in which case you cannot pass it by reference, because C++ doesn't allow references to references) and all kind of meaningful stuff. By means of type_traits, for example, you can write something like this
#include <type_traits>
typedef int& my_type;
void f(const std::add_lvalue_reference<my_type> a){
}
typedef int my_type2;
void g(const std::add_lvalue_reference<my_type2> a){
}
int main() {
}
Of course, this is a made up example, but you can see the utility of the approach, which is much greater if you are using templates. Notice that type_traits are part of the c++11 std library, if you are not using c++11 you have to make your own (or use some library as loki)
When you want to change the int variable, you can use reference too.
For an array, the array name is just a pointer to the first element, when it's used as a parameter passed to a function, it will change to ordinary pointer, so you must pass the number of the elements in the array as a parameter.
Using variables versus pointers to variables as parameters for a function
General recommendations:
If a function does not change parameter, pass by value.
#include <iostream>
int test(int arg){
std::cout << arg;
}
int main(int argc, char** argv){
int a = 6;
test(a);
return 0;
}
If a function needs to change passed parameter, pass by reference.
#include <iostream>
int test(int &arg){
arg = 6;
}
int main(int argc, char** argv){
int a = 0;
test(a);
std::cout << arg;
return 0;
}
If a function does not need to change parameter, but parameter is BIG, pass by const reference.
If a function neeeds to change passed parameter AND this parameter is optional, pass by pointer.
#include <iostream>
int test(int *arg){
if (arg)
*arg = 6;
}
int main(int argc, char** argv){
int a = 0, b = 1;
test(0);
test(&b);
std::cout << a << std::endl << b << std::endl;
return 0;
}
If a function does not neeed to change passed parameter, parameter is big and parameter is optional, pass by pointer to const.
Reasoning: references and pointers can be used to modify values "outside" of function, but references cannot be set to 0/NULL.
pointer to an int (4 bytes)
Depending on the platform, pointer to int may not be 4 bytes big. On 64bit system it'll be 8bytes big, for example.
Returning pointer to int makes sense if that function allocates memory block. Returning pointer/reference to int makes sense if this function is is used as a "selector" and you need to write into returned value.
#include <iostream>
int& getMaxVal(int &a, int &b){
return (a > b)? a: b;
}
int main(int argc, char** argv){
int i = 3, j = 4;
std::cout << i << " " << j << std::endl;
getMaxVal(i, j) /= 2;
std::cout << i << " " << j << std::endl;
return 0;
}

is_function_pointer<> for <type_traits>

There are these in <type_traits>:
is_pointer<>
is_function<>
is_member_function_pointer<>
But not this:
is_function_pointer<>
Why is it so?
The traits in [meta.unary.cat] are intended to classify each type into a single category. Is it a void, integral, pointer, etc. At this level, pointer-to-function is no different than pointer-to-int. And note that a pointer to a member is not a pointer. It is merely an english homonym.
It was intended that every type return true to exactly one trait in [meta.unary.cat]. And in this categorization, both a function pointer and a scalar pointer would both return true under is_pointer.
I will note that we did not achieve our objective. nullptr_t escapes our goal. But we got close. Here is a graphical representation of the current type_traits classification.
Update:
This is a correctly working program with correct output:
#include <iostream>
#include <type_traits>
typedef void (*fptr)();
typedef int* intptr;
int main()
{
std::cout << std::is_function<fptr>::value << '\n';
std::cout << std::is_pointer<fptr>::value << '\n';
std::cout << std::is_pointer<intptr>::value << '\n';
}
0
1
1
It does seem like an odd oversight. However, member pointers are always member pointer types, unlike free functions, which can be either pointers types (void(*)()) or function types (void()). Also std::is_pointer never returns true for member pointer types.
However, if you need this functionality, here's an implementation:
template<typename testType>
struct is_function_pointer
{
static const bool value =
std::is_pointer<testType>::value ?
std::is_function<typename std::remove_pointer<testType>::type>::value :
false;
};

Typedef function pointer?

I'm learning how to dynamically load DLL's but what I don't understand is this line
typedef void (*FunctionFunc)();
I have a few questions. If someone is able to answer them I would be grateful.
Why is typedef used?
The syntax looks odd; after void should there not be a function name or something? It looks like an anonymous function.
Is a function pointer created to store the memory address of a function?
So I'm confused at the moment; can you clarify things for me?
typedef is a language construct that associates a name to a type.
You use it the same way you would use the original type, for instance
typedef int myinteger;
typedef char *mystring;
typedef void (*myfunc)();
using them like
myinteger i; // is equivalent to int i;
mystring s; // is the same as char *s;
myfunc f; // compile equally as void (*f)();
As you can see, you could just replace the typedefed name with its definition given above.
The difficulty lies in the pointer to functions syntax and readability in C and C++, and the typedef can improve the readability of such declarations. However, the syntax is appropriate, since functions - unlike other simpler types - may have a return value and parameters, thus the sometimes lengthy and complex declaration of a pointer to function.
The readability may start to be really tricky with pointers to functions arrays, and some other even more indirect flavors.
To answer your three questions
Why is typedef used?
To ease the reading of the code - especially for pointers to functions, or structure names.
The syntax looks odd (in the pointer to function declaration)
That syntax is not obvious to read, at least when beginning. Using a typedef declaration instead eases the reading
Is a function pointer created to store the memory address of a function?
Yes, a function pointer stores the address of a function. This has nothing to do with the typedef construct which only ease the writing/reading of a program ; the compiler just expands the typedef definition before compiling the actual code.
Example:
typedef int (*t_somefunc)(int,int);
int product(int u, int v) {
return u*v;
}
t_somefunc afunc = &product;
...
int x2 = (*afunc)(123, 456); // call product() to calculate 123*456
typedef is used to alias types; in this case you're aliasing FunctionFunc to void(*)().
Indeed the syntax does look odd, have a look at this:
typedef void (*FunctionFunc) ( );
// ^ ^ ^
// return type type name arguments
No, this simply tells the compiler that the FunctionFunc type will be a function pointer, it doesn't define one, like this:
FunctionFunc x;
void doSomething() { printf("Hello there\n"); }
x = &doSomething;
x(); //prints "Hello there"
Without the typedef word, in C++ the declaration would declare a variable FunctionFunc of type pointer to function of no arguments, returning void.
With the typedef it instead defines FunctionFunc as a name for that type.
If you can use C++11 you may want to use std::function and using keyword.
using FunctionFunc = std::function<void(int arg1, std::string arg2)>;
#include <stdio.h>
#include <math.h>
/*
To define a new type name with typedef, follow these steps:
1. Write the statement as if a variable of the desired type were being declared.
2. Where the name of the declared variable would normally appear, substitute the new type name.
3. In front of everything, place the keyword typedef.
*/
// typedef a primitive data type
typedef double distance;
// typedef struct
typedef struct{
int x;
int y;
} point;
//typedef an array
typedef point points[100];
points ps = {0}; // ps is an array of 100 point
// typedef a function
typedef distance (*distanceFun_p)(point,point) ; // TYPE_DEF distanceFun_p TO BE int (*distanceFun_p)(point,point)
// prototype a function
distance findDistance(point, point);
int main(int argc, char const *argv[])
{
// delcare a function pointer
distanceFun_p func_p;
// initialize the function pointer with a function address
func_p = findDistance;
// initialize two point variables
point p1 = {0,0} , p2 = {1,1};
// call the function through the pointer
distance d = func_p(p1,p2);
printf("the distance is %f\n", d );
return 0;
}
distance findDistance(point p1, point p2)
{
distance xdiff = p1.x - p2.x;
distance ydiff = p1.y - p2.y;
return sqrt( (xdiff * xdiff) + (ydiff * ydiff) );
}
For general case of syntax you can look at annex A of the ANSI C standard.
In the Backus-Naur form from there, you can see that typedef has the type storage-class-specifier.
In the type declaration-specifiers you can see that you can mix many specifier types, the order of which does not matter.
For example, it is correct to say,
long typedef long a;
to define the type a as an alias for long long. So , to understand the typedef on the exhaustive use you need to consult some backus-naur form that defines the syntax (there are many correct grammars for ANSI C, not only that of ISO).
When you use typedef to define an alias for a function type you need to put the alias in the same place where you put the identifier of the function. In your case you define the type FunctionFunc as an alias for a pointer to function whose type checking is disabled at call and returning nothing.

Commutative property a[i] == i[a]

For a built in type integer array say
int a[10];
int i = 2;
a[i] = 10;
alternatively
i[a] = 10;
because
a[i] is a postfix expression that is *(a+i) or *(i+a) because commutative property of addition.
I want to achieve that for a userdefined type say
class Dummy
{
//
};
Is it possible?
If yes then how?
If no then why?
EDIT :-
I know it is ugly but following code compiles :-
g++ -dumpversion
4.3.3
#include <stdio.h>
#include<iostream>
#include <string.h>
#include <malloc.h>
using namespace std;
int main()
{
string ArrayS[10];
2[ArrayS] = "ADASD" ;
cout << 2[ArrayS] << endl;
return 0;
}
It is impossible because "operator[] shall be a non-static member function with exactly one parameter" (standard §13.5.5/1), so you cannot define it such that the first argument is of native scalar type.
(Furthermore, a nonstatic operator overload call is interpreted as a member call, so the first operand cannot be implicitly converted, unlike a free function overload. This is one reason why free function overloads are preferred when possible.)
For better or worse, index[ object ] is a way to ensure that no operator[] overload gets called.
However.
"The expression E1[E2] is identical (by definition) to *((E1)+(E2))" (§5.2.1) and operator+ can be overloaded so long as one side is not native type. This leaves two options vulnerabilities: the "array" must be a class, or the "index" must be a class or enum.
You would then have to define a proxy type to hold the result of "addition," which defines an operator* overload. GCC does not support this, however. I'll look deeper into other platforms and references.
Edit: Ah, §13.6/13 overrides 5.2.1 and declares that, for the sake of interpreting an expression involving class or enumeration type, there are functions T& operator[](std::ptrdiff_t, T*); and T& operator[](T*, std::ptrdiff_t);. So that's that.
With C++, nothing is impossible. It is however, a terrible terrible idea. Don't do this.
#include <memory>
#include <stdlib.h>
#include <stdio.h>
void *aligned_malloc( size_t bytes, size_t alignment ) {
void *p = malloc( bytes + alignment ), *pa = reinterpret_cast<void*>( reinterpret_cast<size_t>(p) + alignment &- alignment );
reinterpret_cast<void**>(pa)[-1] = p;
return pa;
}
void aligned_free( void *pa ) {
void *p = reinterpret_cast<void**>(pa)[-1];
free( p );
}
struct SupportReverseIndexer
{
class IndexerReversal
{
static const size_t alignment;
friend struct SupportReverseIndexer;
friend class std::auto_ptr<IndexerReversal>;
struct SupportReverseIndexer* const m_parent;
IndexerReversal(struct SupportReverseIndexer* parent) : m_parent(parent) {}
void* operator new(size_t bytes) { return aligned_malloc(bytes, alignment); }
void operator delete(void* p) { aligned_free(p); }
static struct SupportReverseIndexer* getParent(IndexerReversal* pThis)
{
size_t iThis = reinterpret_cast<size_t>(pThis);
iThis += alignment >> 1;
iThis &= ~(alignment - 1);
return reinterpret_cast<IndexerReversal*>(iThis)->m_parent;
}
public:
operator size_t() { struct SupportReverseIndexer* const parent = getParent(this); return parent->indexer(this-parent->ir.get()); }
};
SupportReverseIndexer() : ir(new IndexerReversal(this)) {}
operator IndexerReversal*() { return ir.get(); }
private:
std::auto_ptr<IndexerReversal> ir;
size_t indexer(size_t index) { printf("Custom operator[] called, index = %i\n", index); return index; }
};
const size_t SupportReverseIndexer::IndexerReversal::alignment = 0x10000 * sizeof(SupportReverseIndexer::IndexerReversal);
int main(void)
{
SupportReverseIndexer sri;
int a = sri[2];
a = 3[sri];
a = (-5)[sri];
return 0;
}
No, really, DON'T DO THIS!!!!!
It is completely impossible to do. Potatoswatter correctly points out you couldn't possibly define any operator such as operator[](int, T), so overloading for an integer on the left is impossible.
But consider that this works:
struct foo
{
operator const foo*() const
{
return this;
}
};
int main()
{
foo f;
5[f]; // UB
}
Is there a way to utilize this? No:
5.2.1 Subscripting
A postfix expression followed by an expression in square brackets is a postfix expression. One of the expressions shall have the type “pointer to T” and the other shall have enumeration or integral type. The result is an lvalue of type “T.” The type “T” shall be a completely-defined object type.56) The expression E1[E2] is identical (by definition) to *((E1)+(E2)).
With E1 being an integral type, E2 must be a pointer type. So we can't inject user-behavior there.
The only thing left is + and *. We can't change operator+ for an integral type and a pointer, because that's defined by the language. The result of E1 + E2 is going to be a pointer, and we can't define operator* for a pointer either.
Therefore, injecting user-defined behavior is impossible.
a[i] = 10;
i[a] = 10;
because a[i] is a postfix expression that is *(a+i) or *(i+a) because commutative property of addition.
Yes. But a[i] == i[a] == *(a+i) == *(i+a) is because the notation a[i] in C is a syntactic sugar for the latter pointer arithmetic. Keyword here "in C". C++ in large tries to part ways from the pointer arithmetic. Thus the a[i] as a syntactic sugar is only supported on the POD for backward compatibility with the C. But that does not work on any C++ objects since the operations [] has clear semantic specified and it doesn't allow the C-like syntax tricks.
In the end, do not do it. The trick is an obscure remnant of the older times and doesn't have a single good reason to be reincarnated.
Any Dummy that was declared and used as an array will work the same way, if Dummy can be implicitly cast to an integer.
You will need to define the Dummy::operator[](const Dummy& ref) to exhibit the desired property. For instance:
#include <iostream>
class dummy
{
public:
int operator[](const dummy& ref) { return 0; }
};
int main(int argc, char *argv[])
{
dummy d1, d2;
std::cout << (d1[d2] == d2[d1] ? "Yes" : "No");
}
Of course this is probably not exactly what you're looking for, but the tricky bit will be to replace the return 0; and possibly the return type with something that you have to define and that satisfies your intent.
Why exactly would you want this? Is it just a mental exercise?

Determining the type of an expression

Sometimes I need to learn the type of an expression while programming in C or C++. Sometimes there's a good IDE or existent documentation to help me, but sometimes not. I often feel such a construct could be useful:
void (*myFunc)(int);
printf("%s", nameoftype(myFunc)); //"void (*)(int)"
int i, unsigned int u;
printf("%s", nameoftype(i+u)); //"unsigned int"
This is especially true for C++; think accessors of const objects - do they return a const reference or a copy? Think dynamic casts and templated classes.
How can I do this? (i.e. learn the type of an expression)
I use GCC but as far as I know, it does not have such an extension. So I guess I'm curious as to how people solve this problem. (Both compile-time and runtime solutions welcome.)
Sometimes I just do:
int ***a = expression;
and look for the "<expression type> cannot be assigned to pointer-to^3 int" error. This seems to be the most portable workaround.
C++ has a typeid operator;
typeid(expression).name()
would return an implementation-defined name of the type of the expression. Alas, it is usually not human-readable.
What are you looking for? Automatic type inference or looking for the type so you can declare a variable correctly manually? (your own answers look like you want to have the second one). In this case, consider using Geordi:
<litb> make type pointer to function taking pointer to array of 10 int returning void
<geordi> void (*)(int (*)[10])
<litb> geordi: { int a = -1; unsigned int b = 0; cout << ETYPE(a + b), ETYPE_DESC(a + b), (a + b); }
<geordi> rvalue unsigned int, rvalue unsigned integer, 4294967295
<litb> geordi: << TYPE_DESC(void (*)(int (*)[10]))
<geordi> pointer to a function taking a pointer to an array of 10 integers and returning nothing
Automatic type inference is not currently possible without helper libraries like boost.typeof, which will use compiler extensions like __typeof__ for GCC. Next C++ will get auto (with different semantics than current auto) and will be able to do that, together with decltype to get the type of an expression.
If you can live with getting out of local context, you can always create a function template like this:
template<typename T> void f(T t) { /* ... */ }
int main() { int a = -1; unsigned int b = 0; f(a + b); }
Try Boost.Typeof to see if it fits.
gcc has typeof() at compile time. It works like sizeof().
http://gcc.gnu.org/onlinedocs/gcc/Typeof.html has more information.