There is a class that contains some data and it sorts them at some point of time. I use qsort() and I'd like to keep the comparing function within the class as a method. The question is how to pass a method to qsort() so that the compiler (g++) don't throw any warnings?
Attempt 1:
int Data::compare_records(void * rec_1, void * rec_2){
// [...]
}
void Data::sort(){
qsort(records, count, sizeof(*records), &Data::compare_records);
}
This way generates an error:
error: cannot convert ‘int (Data::*)(const void*, const void*)’ to ‘int (*)(const void*, const void*)’ for argument ‘4’ to ‘void qsort(void*, size_t, size_t, int (*)(const void*, const void*))’
Attempt 2 :
void Data::sort(){
qsort(
records, count, sizeof(*records),
(int (*)(const void*, const void*)) &Data::compare_records
);
}
This way generates a warning:
warning: converting from ‘int (Data::*)(const void*, const void*)’ to ‘int (*)(const void*, const void*)’
How to do it the right way then?
If you must use qsort and not std::sort (recommended), declaring the member method as static should be enough.
You pass the function as &Data::compare_records, but you should pass it as Data::compare_records and also make it static
Don't use qsort in C++. Use std::sort and boost/std::bind. Member function-pointer cannot been converted to function-pointer. Your method should be static, or it should be free function.
see Is the type of “pointer-to-member-function” different from “pointer-to-function”? for an explanation.
This code may also help as a hint, for std::sort despite the fact I Use Qt's qSort()
Functors can be very cool.
struct randomWSort
{
SatoshiGame* This;
randomWSort(SatoshiGame* g){This=g;}
bool operator()(QString& a, QString& b)
{
return This->randomWSort(a,b);
}
};
bool SatoshiGame::randomWSort(QString& a, QString& b)
{
return rand->rnd() %2;
}
QString SatoshiGame::getRandomString(QStringList words)
{
qSort(words.begin(), words.end(), ::randomWSort(this) );
return words.at(0);
}
Related
I'm trying to learn how to use pointer to function properly. I was supposed to make a pointer to the function strcmp, inside the function check, but the program opens and closes immediately. As far as I understood, the pointer to function is correct on my code returnType (*pointer)(parameters)); So what is going wrong? Thanks in advance.
void check(char *a,char *b,int (*cmp)(const char*,const char*))
{
printf("Testing equality\n");
if(!(*cmp)(a,b)) printf("equals");
else printf("different");
}
int main(void)
{
char s1[80] = "daniel" ,s2[80] = "daniel";
int (*p)(const char*,const char*);
p = strcmp();
check(s1,s2,p);
return 0;
}
This line is incorrect:
p = strcmp();
Here you're calling strcmp with zero arguments, which is invalid. You should have gotten a very clear compiler error about this. For instance, gcc gives me:
error: too few arguments to function ‘int strcmp(const char*, const char*)’
You want to just assign strcmp:
p = strcmp;
Also, you don't need to dereference function pointers to call them, so !(*cmp)(a,b) could be simplified to !cmp(a,b).
I have a function which takes a function pointer as an argument, and then calls that function with its own arguments:
typedef int (*my_func_ptr)( int );
int foo( my_func_ptr f ) {
static int i = 0;
return i = f( i );
}
Sometimes, I need to pass functions to foo that depend on more than just integer input to spit out a result.
int add_strlen( int i, const char* s ) {
return i + strlen( s );
}
I could rework the above code to make use of std::function and then use std::bind, but it is preferable to me that these functions be created at compile time, so I'm using templates.
template<const char* S>
int add_strlen( int i ) {
return i + strlen( S );
}
/**
* Usage:
* char bar[] = "bar";
* foo( add_strlen<bar> );
*/
My problem arises when using pointers as template arguments. Whenever I use a pointer to constant data of any type as a template argument, it only manages to compile if the argument being passed is declared as a non-const array of that type.
char char_array[] = "works";
const char const_char_array[] = "error";
char *char_ptr = "error";
const char *const_char_ptr = "error";
The relevant error in Clang (ver. 3.0-6) (errors for char_ptr and const_char_ptr are the same):
func_ptr.cpp:29:9: error: no matching function for call to 'foo'
foo( add_strlen<const_char_array> );
^~~
func_ptr.cpp:6:5: note: candidate function not viable: no overload of 'add_strlen' matching 'my_func_ptr' (aka 'int (*)(int)') for 1st argument
int foo( my_func_ptr f )
Can anyone explain to me why this is? The way I see it, template parameter S is expected to be of type const char*, which in any other circumstance means I can pass in any const or non-const pointer or array of type char and expect it to work. I would like to be able to declare my arrays as const, because I don't want to even imply that they are meant to be modified at runtime. Is there any way to keep my arrays const and use them as template arguments?
Edit: Thanks to some help (and a newer version of Clang with better errors) I was able to determine that supplying a template argument with internal linkage is part of the problem. By declaring the above variables as extern, I am able to use add_strlen<const_char_array> without error. I've also created a simplified test case. It is included below:
#include <cstring>
typedef int (*my_func_ptr)( int );
int foo( my_func_ptr f ) {
static int i = 0;
return i = f( i );
}
template<const char* S>
int add_strlen( int i ) {
return i + strlen( S );
}
extern char char_array[];
extern const char const_char_array[];
extern char *char_ptr;
extern const char *const_char_ptr;
char char_array[] = "foo";
const char const_char_array[] = "bar";
// assigning to string literal is deprecated
char *char_ptr = char_array;
const char *const_char_ptr = "baz";
int main(int argc, const char *argv[])
{
foo( add_strlen<char_array> ); // works
foo( add_strlen<const_char_array> ); // works
//foo( add_strlen<char_ptr> ); // doesn't work
//foo( add_strlen<const_char_ptr> ); // doesn't work
return 0;
}
The error seems to be related to what you are and what you are not allowed to use as non-type template parameters, referring to IBM Linux Compilers documentation for Non-type template parameters they have this to say:
The syntax of a non-type template parameter is the same as a declaration of one of the following types:
integral or enumeration
pointer to object or pointer to function
reference to object or reference to function
pointer to member
The reason why char_array[] and const_char_array[] work when passed in is because they are constant at compile time and will never change underneath the program while it is running. Integral types can be passed in, pointers to integral types however can not be passed in.
The template is expecting a type of const char * a.k.a const char[x], but it is also expecting something that will never change, so the location where the pointer is pointing may never change. When passed in at compiler time your const_char_array it is being passed a char[6] ("error"). The location will never change and the contents will never change. However when passing in the const_char_ptr it is getting a const char *, while the pointer itself may never change, it is entirely possible the location where it points may change. It itself is not static.
char *_arr = new char[20];
const char* _ptr_arr = _arr;
We can agree here that my _ptr_arr is the exact same type as your const_char_ptr, yet the location where the contents are stored may change at run-time. In templates that isn't allowed since it may require a whole new instantiation of the template, and is non-deterministic from when templates are created. A char [6] is static and won't change.
foo( add_strlen<_ptr_arr> );
results in the following compiler error:
test.cpp:36:5: error: no matching function for call to 'foo'
foo( add_strlen<_ptr_arr>);
^~~
test.cpp:6:5: note: candidate function not viable: no overload of 'add_strlen' matching 'my_func_ptr' (aka 'int (*)(int)') for 1st argument
int foo( my_func_ptr f ) {
^
Which is not very helpful, we want to figure out why there is no valid overload, compiling the code with the function stand-alone without being passed as a function pointer we get the following:
add_strlen<_ptr_arr>(0);
will result in:
test.cpp:36:5: error: no matching function for call to 'add_strlen'
add_strlen<_ptr_arr>(0);
^~~~~~~~~~~~~~~~~~~~
test.cpp:16:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'S'
int add_strlen( int i ) {
^
So the explicitly-specified argument is invalid, specifically, we can't pass in an pointer to an integral.
I am trying to make a constructor for class call, in which 4 arrays are passed as parameters. I've tried using *,&, and the array itself; however when I assign the values in the parameters to the variables in the class, I get this error :
call.cpp: In constructor ‘call::call(int*, int*, char*, char*)’:
call.cpp:4:15: error: incompatible types in assignment of ‘int*’ to ‘int [8]’
call.cpp:5:16: error: incompatible types in assignment of ‘int*’ to ‘int [8]’
call.cpp:6:16: error: incompatible types in assignment of ‘char*’ to ‘char [14]’
call.cpp:7:16: error: incompatible types in assignment of ‘char*’ to ‘char [14]’
I would appreciate your help in finding my error and helping me correct it.
here is my code:
.h file
#ifndef call_h
#define call_h
class call{
private:
int FROMNU[8];
int DESTNUM[8];
char INITIME[14];
char ENDTIME[14];
public:
call(int *,int *,char *,char *);
};
#endif
.cpp file
call:: call(int FROMNU[8],int DESTNUM[8],char INITIME[14],char ENDTIME[14]){
this->FROMNU=FROMNU;
this->DESTNUM=DESTNUM;
this->INITIME=INITIME;
this->ENDTIME=ENDTIME;
}
Raw arrays are non-assignable and generally difficult to handle. But you can put an array inside a struct, and assign or initialize that. Essentially that's what std::array is.
E.g. you can do
typedef std::array<int, 8> num_t;
typedef std::array<char, 14> time_t;
class call_t
{
private:
num_t from_;
num_t dest_;
time_t init_;
time_t end_;
public:
call_t(
num_t const& from,
num_t const& dest,
time_t const& init,
time_t const& end
)
: from_t( from ), dest_( dest ), init_( init ), end_( end )
{}
};
But this still lacks some essential abstraction, so it's merely a technical solution.
To improve things, consider what e.g. num_t really is. Is it, perhaps, a telephone number? Then model it as such.
Consider also using standard library containers std::vector and, for the arrays of char, std::string.
Passing a raw array as an argument is possible in C++.
Consider the following code:
template<size_t array_size>
void f(char (&a)[array_size])
{
size_t size_of_a = sizeof(a); // size_of_a is 8
}
int main()
{
char a[8];
f(a);
}
In C/C++ you cannot assign arrays by doing this->FROMNU=FROMNU; thus your method wont work, and is one half of your error.
The other half is that you try to assign a pointer to the array. Even if you pass arrays to a function, they decay to pointers to the first element, despite what you say in the definition.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
void pointers: difference between C and C++
Hi I have the following function:
void task2(int a)
{
printf(" Task 2 running..\n");
sleep(2);
printf(" Task 2 exiting..\n");
}
thpool_add_work(threadpool, (void*)task2, (void*)a);
int thpool_add_work(thpool_t* tp_p, void *(*function_p)(void*), void* arg_p)
{
// some code here
}
The above code works well with C, but does not compile in C++. I'm getting the following error:
error: invalid conversion from ‘void*’ to ‘void* (*)(void*)’
error: initializing argument 2 of ‘int thpool_add_work(thpool_t*, void* (*)(void*), void*)’
I'm not able to figure out the reason for this error. Any idea why this error crops up when I change the file extension to CPP and compile?
You have to change the signature of task2 to match the type of the thpool_add_work argument:
void* task2(void* a)
The call which creates the thread would become
thpool_add_work(threadpool, task2, &a);
assuming that a is int.
If you need to use the argument of task2, you could do following:
int ia = *(int*)a;
Update to answer the OP comment
thpool_add_work expects a function with void* argument for a reason. In such a way, you can pass any kind of parameter into the thread function, albeit in a type-unsafe way.
You pass the address of the parameter converted to void* as the 3rd argument of thpool_add_work. Afterwards, you cast a pointer to void back to the pointer to your expected parameter type and dereference it to get the value of the parameter. I gave the example for int a above, now how it would look for a float:
void* test3(void* a)
{
float fa = *(float*)a;
.....
return NULL;
}
Try this
thpool_add_work(threadpool, (void* (*)(void*))task2, (void*)a);
C converts void* to any type automatically, C++ does not.
You could improve the code with a typedef
typedef void* (*worker_func_t)(void*);
thpool_add_work(threadpool, (worker_func_t)task2, (void*)a);
int thpool_add_work(thpool_t* tp_p, worker_func_t function_p, void* arg_p)
{
// some code here
}
I am trying to create an inline function for a comparer to qsort - something like this:
function<int(int,int)> comparesort = [smarkers, emarkers, strSearch] (int *arg1, int *arg2) { return 0; };
qsort(sortptrs, nKeywords, sizeof(int), comparesort);
It's giving me this error
IntelliSense: no suitable conversion function from "std::tr1::function" to "int (__cdecl *)(const void *, const void *)" exists
ok - I changed it to this
auto comparesort = [sortptrs, smarkers, emarkers, strSearch] (int arg1, int arg2)
{
int a = 0;
.
.
.
return a;
};
std::sort(sortptrs, sortptrs + nKeywords, comparesort);
and it's giving an error:
error C3499: a lambda that has been specified to have a void return type cannot return a value
[edit on 7/30 3:55 pm]
I actually needed a pointer sort - I've got an array of start and end bytes of words (found in a string passed in from VB.Net managed code). I also have a pointer-array that contains "1,2,3..." and I needed to sort the pointer.
Didn't seem I could do that with std::sort so I implemented my own shell sort...
The signature of qsort takes a function pointer of type int(*)(const void*, const void*). You are trying to give it a function<int(int, int)>, which is not a function pointer, but an object encapsulating something (might be a function ptr, might be a functor) which is callable as int(int, int) (note that it wouldn't have the right signature, even if it was a function pointer).
qsort is a basically a legacy function for backward compatibility with c.
In c++ I would strongly suggest forgetting about it and using std::sort instead:
auto comparesort = [smarkers, emarkers, strSearch] (const int& arg1, const int& arg2) { return false; };
//directly store the lambda, avoiding the overhead of creating a `function<...>`
std::sort(sortptrs, sortptrs + nKeywords, comparesort);
qsort is the old C API that takes a function pointer directly. You can't use it with anything else such as lambdas. Instead, use std::sort.