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.
Related
I've used std::bind before and I think am close on this usage but not quite there and I don't have a clue how to resolve the compile error.
The ultimate goal is a medium-sized array of pointers to a small number of functions, with different parameters in each array element. At this point I just have one function and one table entry. If I can get that right I think I can solve the rest. I want to use std::function so that I can put the varied parameters into the array.
Here's declaration of the one function so far:
static Get *MakeGArrayStatic(void *Subscript, const void **array, unsigned int sizeOfArray);
Here's the declaration of the single pointer that will be typical of the array:
typedef std::tr1::function<Get *(void *, const void**, unsigned int)> GetMaker;
static GetMaker *gm1;
Here's the definition of the pointer:
Get::GetMaker *Get::gm1 = std::tr1::bind(&MakeGArrayStatic, &OutMsg::CurrentSeverity, FacSevTbls::SyslogSeveritiesForMessages, FacSevTbls::NumberOfTrueSeverities);
(Get is a class, CurrentSeverity is an enum, SyslogSeveritiesForMessages is a const char **, and NumberOfTrueSeverities is a size_t.)
The error I am getting (VS 2010) is
error C2440: 'initializing' : cannot convert from 'std::tr1::_Bind<_Result_type,_Ret,_BindN>' to 'Get::GetMaker *'
with
[
_Result_type=Get *,
_Ret=Get *,
_BindN=std::tr1::_Bind3,SyslogEnums::SeverityEnum *,const char **,size_t>
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
Can anyone please point out where I am going wrong?
Thank you again to #PlinyTheElder but I think we have left the question "officially" unanswered. Closing the loop, here are the declarations with the first cut at an array of functions:
static Get *MakeGArrayStatic(void *Subscript, const char **array, size_t sizeOfArray);
static Get *MakeGStatic(void *field, size_t sizeOfField);
typedef std::tr1::function<Get *()> GetMaker;
static GetMaker gm[];
and here is the definition of the array so far:
std::tr1::function<Get *()> Get::gm[] = {
std::tr1::bind(&Get::MakeGArrayStatic, &OutMsg::CurrentSeverity, FacSevTbls::SyslogSeveritiesForMessages, FacSevTbls::NumberOfTrueSeverities),
std::tr1::bind(&MakeGStatic, Msg::MessageID, 8) } ;
And here is a trivial example of a call to a function:
Get *g = Get::gm[0]();
Came out better than I had hoped. I had pictured that all of the "little functions" were going to have to have the same signature (like overloads). Compiles cleanly on both target compilers. (Have not tested execution yet, but I am confident.) Thanks again!
Update: yes, it executes.
I have an issue about pushing structs allocated with new operator.
Here follows my queue declaration, my struct and the code where I allocate a new struct and try to push it in my queue:
std::queue<data_pkt> my_queue;
typedef struct data_pkt {
int sockfd;
std::string payload;
int payload_size;
} data_packet;
data_packet *data = new data_packet;
if (!data) {
printf("Failed to allocate data_packet to enqueue pkt\n");
exit(EXIT_FAILURE);
}
/* filling struct's fields... */
my_queue.push(data);
When compiling with flags -Wall -std=c++11, it gives:
error: no matching function for call to ‘std::queue<data_pkt>::push(data_packet*&)’
queue_to_internet_1.push(data);
no known conversion for argument 1 from ‘data_packet*
{aka data_pkt*}’ to ‘const value_type& {aka const data_pkt&}’
So I tried changing my queue declaration including &, so that it could accept pointers to struct, but it says:
error: template argument 1 is invalid
std::queue<&data_pkt> q;
^
QOSManager.h:57:23: error: template argument 2 is invalid
I saw that new returns a void *, so my queue should be capable of storing pointers to data_packet structs, but I don't know what I'm doing wrong.
In your code compiler produce syntax error about push of value of wrong type,
that can be fixed by:
my_queue.push(*data);
side note in C++ you not need typedef struct data_pkt{} data_packet;
you can write struct data_packet {}; and then write data_packet data;,
without struct keyword, because of C++ not C.
But your memory allocation is waste of CPU cycles,
so you can write:
data_pkt data;
my_queue.push(data);
Or to remove useless copy:
my_queue.push(data_pkt());
data_pkt &data = my_queue.back();
//fill data here
Two options to fix compilation error:
Do not use dynamic allocation as already mentioned.
Store pointers in the queue instead of structs and this is correct declaration for this std::queue<data_pkt*> my_queue;
Well, templates and std:: library is a big topic, but to quickly understand where the compiler error comes from - consider the my_queue as plain array. You either declare array of structures and set structure in each element or you declare array of pointers and set pointers.
The following two programs are really confusing me. In the first program I use const char* and I can reassign the string. In the second example I use a const char[] and now I can no longer reassign the string. Could someone please explain why this is?
#include <iostream>
using namespace std;
const char* x {"one"};
void callthis(const char t[]);
int main()
{
callthis("two");
return 0;
}
void callthis(const char t[]){
t=x; // OK
// OR
// x=t; // OK
}
Second:
#include <iostream>
using namespace std;
const char x[] {"three"};
void callthis(const char* t);
int main(){
callthis("four");
return 0;
}
void callthis(const char* t){
x=t; // error: assignment of read-only variable 'x';
// error : incompatible types in assignment of
// 'const char*' to 'const char [6]'
}
An array is not a pointer. Lets cover that again: An array is not a pointer
Arrays cannot be assigned to. Once the are declared if the are not initialized at that time the only way to set the value of the array is to iterate to each element and set its contents. The const on the array is a red hearing, if we were to use
char x[] {"three"};
//...
void callthis(const char* t){
x=t;
}
We would still get an error like:
error: array type 'char [6]' is not assignable
The reason the first example works is that pointers can be assigned to and a const char * is not a constant pointer but a pointer to a constant char. Since the pointer is not const where can change what the pointer points to. If you were to use
const char * const x {"one"};
Then you have received an error along the lines of
error: cannot assign to variable 'x' with const-qualified type 'const char *const'
I also noticed you are using using namespace std; in you code. In small examples it doesn't really hurt anything but you should get into the habit of not using it. For more information on why see: Why is “using namespace std” in C++ considered bad practice?
I found this code in the rendering library for Quake 3. There is this function:
void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int fogIndex, int dlightMap );`
It is being called in a loop somehwere else like this:
R_AddDrawSurf( ( void * )poly, sh, poly->fogIndex, qfalse );
The weird part is that poly was declared as srfPoly_t *poly. What is going on
here? It is casting a srfPoly_t object to (void *) and then entering the
function as a surfaceType_t object.
Here are the declaration for the relevant structs:
typedef enum {
SF_BAD,
SF_SKIP, // ignore
SF_FACE,
SF_GRID,
SF_TRIANGLES,
SF_POLY,
SF_MD3,
SF_MD4,
SF_FLARE,
SF_ENTITY, // beams, rails, lightning, etc that can be determined by entity
SF_DISPLAY_LIST,
SF_NUM_SURFACE_TYPES,
SF_MAX = 0x7fffffff // ensures that sizeof( surfaceType_t ) == sizeof( int )
} surfaceType_t;
typedef struct srfPoly_s {
surfaceType_t surfaceType;
qhandle_t hShader;
int fogIndex;
int numVerts;
polyVert_t *verts;
} srfPoly_t;
This is working in C, but I am trying to implement something similar in C++,
but I get the following error:
Error 1 error C2664: 'int RefDef::AddDrawSurf(surfaceType_t *)' : cannot convert argument 1 from 'void *' to 'surfaceType_t *'
It would appear I cannot perform this type of cast in C++, or maybe there is
something else I am unable to understand. I am not very familiar with C++ and
would love to figure out how to set up something similar using it.
I am assuming this has something to do with type checking in C++, so it is not
allowed. How can I implement something similar in C++ in a safe way?
This works in C because structs are simply blocks of memory with each element in the struct laid out consecutively. This cast works because the first n bytes of a srfPoly_t struct consist of the surfaceType_t enum within that struct. The called function tries to interpret the passed-in srfPoly_t as a surfaceType_t, and succeeds because the first n bytes of the argument are, in fact, a surfaceType_t. Do not do this without a very good reason.
Casts from void*'s do not automatically occur in C++ as they do in C. You can use reinterpret_cast to explicitly cast between two different types of structs:
srfPoly_t* mySrfPoly_t;
surfaceType_t* mySurfaceType = reinterpret_cast<surfaceType_t*>(mySrfPoly_t);
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.