I have two types of events with associated values such as:
struct EventRequest
{
char EventType;
int RetryCount;
} ER;
struct EventStatus
{
char EventType;
char StatusType;
short RetryCount;
} ES;
I want to push the above structs onto one single queue/stack such as:
queue<typedef>q;
q.push(ER);
q.push(ES);
q.push(ER):
.
.
.
How can I do that?
One solution to this would be polymorphism: both structs inheriting from a common base class. However, that implies an "is-a" relationship that may not exist and would make your code awkward and harder to understand. With that in mind, another solution to this (since C++ 17) would be std::variant.
#include <queue>
#include <variant>
struct EventRequest {
char EventType;
int RetryCount;
} ER;
struct EventStatus {
char EventType;
char StatusType;
short RetryCount;
} ES;
int main() {
std::queue<std::variant<EventRequest, EventStatus>> q;
q.push(ER);
q.push(ES);
return 0;
}
There are several solution to that problem:
Make all strutures to inherit from a same base interface and use smart pointers.
Use unions (old-style)
For this example, I am going to show how to use std::variant
#include <variant>
#include <queue>
struct EventRequest
{
char EventType;
int RetryCount;
};
struct EventStatus
{
char EventType;
char StatusType;
short RetryCount;
};
using AnyEvent = std::variant<EventRequest, EventStatus>;
int main()
{
std::queue<AnyEvent> event;
event.push(EventRequest());
event.push(EventStatus());
return 0;
}
Run this code here:
https://onlinegdb.com/D17aVXA1K
Related
I'm trying to do a C wrapper for a C++ third-party library because I need to use it in my C project.
I've seen examples of a C++ class wrapper but I don't undertood the process and I can't wrapper a C++ struct.
struct I want to wrapper:
struct confGlobal{
long int device;
string name;
int number;
string uid;
string message;
bool mode;
confiGlobal():device{LONG_MAX}, number{INT_MAX}{}
};
struct product{
string id;
string name;
};
struct category{
unsigned char id;
string name;
string description;
category():id{UCHAR_MAX}{}
};
struct subCategory{
unsigned char id;
string name;
string description;
unsigned char idRoot;
subCategory():id{UCHAR_MAX}, idRoot{UCHAR_MAX}{}
};
struct confPartner{
vector<struct product> tableProduct;
vector<struct category> tableCategory;
vector<struct subCategory> tableSubCategory;
};
For call to this method:
class my_API {
public:
static my_API* Instance(struct confGlobal cGlobal,
struct confPartner cPartner);
... another methods ...
private:
virtual ~my_API();
struct confGlobal cGlobal;
struct confPertner cPartner;
};
I need to fill this structs and call my_API::Instance() from C but my attempts have been unsuccessful.
wrapper.h
#ifdef __cplusplus
extern "C" {
#endif
struct confGlobal_wpr; // An opaque type that we'll use as a handle
typedef struct confGlobal_wpr confGlobal_wpr;
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode);
struct product_wpr{
char id[4];
char name[30];
};
typedef struct product_wpr product_wpr;
struct category_wpr{
unsigned char id;
char name[3];
char description[30];
};
typedef struct category_wpr category_wpr;
struct subcategory_wpr{
unsigned char id;
char name[3];
char description[30];
unsigned char idRoot;
};
typedef struct subCategory_wpr subCategory_wpr;
struct confPartner_wpr; // An opaque type that we'll use as a handle
typedef struct confPartner_wpr confPartner_wpr;
confPartner_wpr *confPartner_create(Product_wpr tableProducts[],
unsigned char numProducts,
Category_wpr tableCategories[],
unsigned char numCategories,
SubCategory_wpr tableSubCategories[],
unsigned char numSubCategories);
struct my_api_wpr;
typedef struct my_api_wpr my_api_wpr;
my_api_wpr *my_api_create(struct confGlobal_wpr cGlobal,
struct confPartner_wpr cPartner);
#ifdef __cplusplus
}
#endif
wrapper.cpp
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode)
{
confGlobal_wpr *cg;
struct confGlobal confiGlobal;
confiGlobal.name = name;
confiGlobal.device = device;
confiGlobal.number = number;
confiGlobal.uid = uid;
confiGlobal.message = message;
if (mode == 0)
confiGlobal.mode = false;
else
confiGlobal.mode = true;
return cg;
}
void confGlobal_destroy(confGlobal_wpr *cg)
{
if (cg == NULL)
return;
delete static_cast<confGlobal_wpr *>(cg->instance); // ERROR: invalid static_cast from type ‘confGlobal’ to type ‘confGlobal_wpr*’
free(cg);
}
confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
unsigned char numProducts,
category_wpr tableCategories_wpr[],
unsigned char numCategories,
subCategory_wpr tableSubCategories_wpr[],
unsigned char numSubCategories)
{
unsigned char i=0;
confPartner_wpr *cc;
struct confPartner cPartner;
vector< struct product> tableProduct;
vector< struct category> tableCategory;
vector< struct subCategory> tableSubCategory;
for (i=0; i<numProducts; i++)
{
struct product p;
p.id = tableProducts_wpr[i].id;
p.name = tableProducts_wpr[i].name;
tableProduct.push_back(p);
}
cPartner.tableProduct = tableProducts;
for (i=0; i<numCategories; i++)
{
struct category c;
c.id = tableCategories_wpr[i].id;
c.nombre = tableCategories_wpr[i].name;
c.descripcion = tableCategories_wpr[i].description;
tableCategory.push_back(c);
}
cPartner.tableCategory = tableCategory;
for (i=0; i<numSubCategories; i++)
{
struct subZona sc;
sc.id = tableSubCategories_wpr[i].id;
sc.name = tableSubCategories_wpr[i].name;
sc.description = tableSubCategories_wpr[i].description;
sc.idRoot = tableSubCategories_wpr[i].idRoot;
tableSubCategory.push_back(sc);
}
cPartner.tableSubCategory = tableSubCategory;
return cc;
}
my_api_wpr *my_api_create(struct confGlobal_wpr confiGlobal_wpr,
struct confPartner_wpr confiPartner_wpr)
{
my_api_wpr *my_api;
my_API *obj;
my_api = (typeof(my_api))malloc(sizeof(*my_api));
obj = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
/* With this compile and linked OK
confGlobal cg;
confPartner cc;
obj = my_API::Instance(cg, cc);
*/
my_api->obj = obj;
return my_api;
}
void my_api_destroy(ct_api_wpr *my_api)
{
if (my_api == NULL)
return;
delete static_cast<my_API *>(my_api->ptr_api); // ERROR: ‘virtual my_API::~my_API()’ is private within this context
free(my_api);
}
The output error when compile and linked with:
g++ -shared -o libwrapper.so *.cpp wrapper.h -l:libthird-party.a -L. -ldl -lrt -Wl,-rpath /usr/local/lib -lc
In function ‘my_api_wpr* my_api_create(confGlobal_wpr, confPartner_wpr)’:
error: no matching function for call to ‘my_API::Instance(confGlobal_wpr&, confPartner_wpr&)’
obj = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
^
my_API.h:30:20: note: candidate: static my_API* my_API::Instance(confGlobal, confPartner)
static my_API* Instance(struct confGlobal cGlobal, struct confiPartner cPartner);
^~~~~~~~
my_API.h:30:20: note: no known conversion for argument 1 from ‘confGlobal_wpr’ to ‘confGlobal’
You're forgetting that CT_API::Instance doesn't understand the "handle" types that you have created in C to wrap the C++ structures. This is precisely what the error message is telling you, if you read it. You must translate those back to the appropriate C++ types.
Firstly, since you are using "create"-style routines to build the structures and return them as a pointer, you should consider making your my_api_create function accept pointers instead. Particularly because the resulting handle types are forward-declared structs with no definition visible in C and it will not be possible for your C client to dereference them.
That highlights another issue. You are also not using these handles correctly from C++.
So, one thing at a time...
Your creation routine in C should be declared as:
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner);
On the C++ side, you need to actually define your handle types. Something like:
extern "C" struct confGlobal_wpr {
struct confGlobal instance;
};
extern "C" struct confPartner_wpr {
struct confPartner instance;
};
extern "C" struct my_api_wpr {
my_API *ptr;
};
Now, your creation:
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode)
{
confGlobal_wpr *cg = new confGlobal_wpr;
struct confGlobal& cGlobal = cg->instance; //<-- note the reference
// TODO: populate cGlobal as usual
return cg;
}
confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
unsigned char numProducts,
category_wpr tableCategories_wpr[],
unsigned char numCategories,
subCategory_wpr tableSubCategories_wpr[],
unsigned char numSubCategories)
{
confPartner_wpr *cc = new confPartner_wpr;
struct confPartner& cPartner = cc->instance; //<-- note the reference
// TODO: populate cPartner as usual
return cc;
}
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner)
{
my_api_wpr *my_api = new my_api_wpr;
my_api->ptr = CT_API::Instance(cGlobal->instance, cPartner->instance);
return my_api;
}
You should also add corresponding _destroy methods for all the above.
To use C++ code in C project you need define wrapper functions with C calling convention - extern "C"(turning off C++ name mangling/decoration) , and call them and only them in your C project. Inside those C functions you can use C++ code. Pass to C wrapper functions only types that C understands. You can create intermediate structures for passing data to C wrapper functions. Then you need copy data to types that C++ class expects. In you particular case you incorrectly pass confGlobal_wpr wrapper struct but C++ method requires confGlobal, and compiler complains on this directly.
Below is observable snippet how to use C++ code from C code:
Foo.h
#include <string>
class Bar
{
public:
Bar(std::string s) : s_(s)
{
}
std::string s_;
};
class Foo
{
public:
Foo(Bar) {}
};
CWrappers.h // include this header to C project
struct BarWrapper
{
char data[100] = "";
};
#ifdef __cplusplus
extern "C" {
#endif
BarWrapper createFoo(char *c);
#ifdef __cplusplus
}
#endif
Wrapper.cpp
#include <algorithm>
#include "Foo.h"
#include "CWrappers.h"
// input and output to this C function should be understandable for C
BarWrapper createFoo(char *c)
{
// inside you can use C++
std::string data(c);
Bar bar(data);
Foo * foo = new Foo(bar);
BarWrapper barWrapper;
std::copy(data.begin(), data.end(), barWrapper.data);
return barWrapper; // pack data to C struct wrapper (that has no C++ specific)
}
C Project
#include "CWrappers.h"
int main()
{
BarWrapper barWrapper = createFoo((char *)"test");
}
Structs that contain anything other than primitive data types common to C and C++ largely can't be wrapped in the way you want. In this particular case, you have ::std::strings in your struct. And they definitely can't be accessed reasonably from C at all.
Additionally, the structs contain bool and I don't know if newer versions of the C standard have bool or define it in such a way that it will result in layout compatible structs with C++ implementations on the same platform.
There are solutions to this problem. But they involve using opaque pointers to the struct in C, and always calling functions to access its methods. I will try to whip up an example of how this might work for a really simple struct.
Looking more carefully at your code, it looks like you need a sort of thunk layer that takes the C struct and (in C++) hand-converts it to the C++ struct and returns a pointer to a dynamically allocated C++ struct that you can then pass to other C++ functions that have been exposed to C.
my code:
#include <iostream>
using namespace std;
struct widget
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val;
};
int main()
{
widget prize =
{"Rolls", 0, "A2X"};
return 0;
}
The problem is with initialization "A2X" when initializing a union in a structure. Compiler doesn't know I want to choose second option with array of chars when I am passing "A2X", it's requiring long type. When I put
char id_char[20]
before
long id_num
everything is ok. But I want to know how to enforce compiler to accept "A2X" with char as the second option in union. Thank for your help.
But I want to know how to enforce compiler to accept "A2X" with char as the second option in union.
You can use a constructor:
id(char const *id_char) {
std::strcpy(this->id_char, id_char);
}
Alternatively you could use a widget constructor.
A drawback is that the compiler probably won't be able to warn you if you use a too large input string for initialization. The shown trivial constructor can be expanded with strlen to check overflow at runtime. I suggest throwing an exception if you choose to check.
This works with -std=c++11:
#include <cstring>
#include <stdexcept>
struct widget
{
char brand[20];
int type;
union id
{
long id_num;
char id_char[20];
}id_val;
widget(char const*Str, int Type, char const *Id);
};
widget::widget(char const*Str, int Type, char const *Id)
{
if (strlen(Str)+1 > sizeof brand)
throw std::length_error{"brand too large"};
memcpy(brand,Str,strlen(Str)+1);
type = Type;
if (strlen(Id)+1 > sizeof id_val.id_char)
throw std::length_error{"id too large"};
memcpy(id_val.id_char,Id,strlen(Id)+1);
}
int main()
{
widget prize = {"Rolls", 0, "A2X"};
return 0;
}
i'm a iOS programer from china, I'm so sorry that i can't make an exact title for this question, but i'll try to describe it detailed. If there are any one can help me to change the title, i'm very thankful about that. Sorry for my bad English.
When i using clang -rewrite-objc to see the source code about the Block Syntax, i found there is something that i can't understand. Here is my code:
int main(int argc, char *argv[]) {
void (^blk)() = ^ {
};
blk();
}
And the core source code is
struct __block_impl {
void *isa;
int Flags;
int Reserved;
void *FuncPtr;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
static void __main_block_func_0(struct __main_block_impl_0 *__cself) {
}
static struct __main_block_desc_0 {
size_t reserved;
size_t Block_size;
} __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)};
int main(int argc, char *argv[]) {
void (*blk)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA));
((void (*)(__block_impl *))((__block_impl *)blk)->FuncPtr)((__block_impl *)blk);
}
In the main function, when i call the blk(), the source code cast blk and take the FuncPtr by this code
((__block_impl *)blk)->FuncPtr)
I can't really understand that, is it supposed to do? In my opinion, i prefer to use
(((__main_block_impl_0 *)blk ->impl).FuncPtr)
I don't really know more about C++, if there is anyone who can help me to understand the principle of this code, i'll be very thankful. Thanks for you guys.
Well, struct __main_block_impl_0's first member (impl) is a struct __block_impl. So the location of the struct __main_block_impl_0 is the same as the location of the struct __block_impl that is its first member. If you have the pointer to one you can just treat it as a pointer to the other.
I'm new to C++/CLI and are having a hard time with Lists.
I have a structure
#using namespace System::Collections::Generic
struct myStruct {
unsigned int A ;
int B; };
and i want to create a list with mystructs
List<myStruct> myList;
But that seems not to work, Visual Studio says
"myStruct is not a valid generic Argument", but why is that so?
And how can i make this structure a "valid generic argument"?
#include <List>
struct myStruct {
unsigned int A ;
int B;
};
std::list<myStruct> myList;
int main(void) {
return 0;
}
I have a class with private member variables declared in a header file. In my constructor, I pass in some filenames and create other objects using those names. This works fine. When I try to add another member variable, however, and initialize it in the constructor, I get an access reading violation. I sent the code to someone else and it works fine on his computer. Any idea what could be wrong?
Here is the offending code:
The .h file:
class QUERYMANAGER {
INDEXCACHE *cache;
URLTABLE *table;
SNIPPET *snip;
int* iquery[MAX_QUERY_LENGTH];
int* metapointers[MAX_QUERY_LENGTH];
int blockpointers[MAX_QUERY_LENGTH];
int docpositions[MAX_QUERY_LENGTH];
int numberdocs[MAX_QUERY_LENGTH];
int frequencies[MAX_QUERY_LENGTH];
int docarrays[MAX_QUERY_LENGTH][256];
int qsize;
public:
QUERYMANAGER();
QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname);
~QUERYMANAGER();
This is the .cpp file:
#include "querymanagernew.h"
#include "snippet.h"
using namespace std;
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname){
cache = new INDEXCACHE(indexfname, btfname);
table = new URLTABLE(urltablefname);
snip = new SNIPPET(snippetfname, snippetbtfname);
//this is where the error occurs
qsize = 0;
}
I am totally at a loss as to what is causing this - any ideas?
Thanks, bsg
Suggestion, factor out the arrays:
class QUERYMANAGER
{
// Snip
int* iquery[MAX_QUERY_LENGTH];
int* metapointers[MAX_QUERY_LENGTH];
int blockpointers[MAX_QUERY_LENGTH];
int docpositions[MAX_QUERY_LENGTH];
int numberdocs[MAX_QUERY_LENGTH];
int frequencies[MAX_QUERY_LENGTH];
int docarrays[MAX_QUERY_LENGTH][256];
int qsize;
// Snip
};
Looks like you should have another structure:
struct Info
{
int* iquery;
int* metapointers;
int blockpointers;
int docpositions;
int numberdocs;
int frequencies;
int docarrays[256];
};
And the QueryManager now looks like:
class QueryManager
{
INDEXCACHE *cache;
URLTABLE *table;
SNIPPET *snip;
int qsize;
Info details[MAX_QUERY_LENGTH];
};
This may help encapsulate themes a little better.
Your dependencies are probably not right, and the necessary files aren't getting rebuilt. Try a "clean" rebuild.
As a note to style, use initializer lists.
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname,
char *snippetfname, char *snippetbtfname) :
cache(new INDEXCACHE(indexfname, btfname)),
table(new URLTABLE(urltablefname)),
snip(new SNIPPET(snippetfname, snippetbtfname)),
qsize(0)
{
}
and you may not need to make those items pointers:
class QUERYMANAGER {
INDEXCACHE cache;
URLTABLE table;
SNIPPET snip;
...
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname,
char *snippetfname, char *snippetbtfname) :
cache(indexfname, btfname),
table(urltablefname),
snip(snippetfname, snippetbtfname),
qsize(0)
{
}
Have you built clean? Since accessing the last member variable blows up, but assigning to earlier ones works OK, either you're not constructing/allocating the instance right when you do use it, or you have object files that refer to older versions of the header that didn't have qsize in the object yet, and thus aren't allocating enough space. Or something along those lines.
As expected, this runs just fine on my machine:
#include <cstdlib>
struct INDEXCACHE {};
struct URLTABLE {};
struct SNIPPET {};
const std::size_t MAX_QUERY_LENGTH = 256;
class QUERYMANAGER {
INDEXCACHE *cache;
URLTABLE *table;
SNIPPET *snip;
int* iquery[MAX_QUERY_LENGTH];
int* metapointers[MAX_QUERY_LENGTH];
int blockpointers[MAX_QUERY_LENGTH];
int docpositions[MAX_QUERY_LENGTH];
int numberdocs[MAX_QUERY_LENGTH];
int frequencies[MAX_QUERY_LENGTH];
int docarrays[MAX_QUERY_LENGTH][256];
int qsize;
public:
QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname);
};
QUERYMANAGER::QUERYMANAGER(char *indexfname, char *btfname, char *urltablefname, char *snippetfname, char *snippetbtfname)
: cache(new INDEXCACHE(/*indexfname, btfname*/))
, table(new URLTABLE(/*urltablefname*/))
, snip(new SNIPPET(/*snippetfname, snippetbtfname*/))
, qsize(0)
{
}
int main()
{
QUERYMANAGER foo("blargl", "frxnl", "wrgxl", "brlgl", "srgl");
return 0;
}
So the error must be in the code you're not showing.
BTW, all upper-case names are boo except for macros. They're making your code harder to read and confuse everyone used to a more common coding style.