Could someone offer me some guidance on what I am doing wrong here, please.
I have a set of different structures in a library which I cannot edit:
typedef struct __mavlink_heartbeat_t
{
uint8_t type; ///< Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM)
uint8_t autopilot; ///< Type of the Autopilot: 0: Generic, 1: PIXHAWK, 2: SLUGS, 3: Ardupilot (up to 15 types), defined in MAV_AUTOPILOT_TYPE ENUM
uint8_t mavlink_version; ///< MAVLink version
} mavlink_heartbeat_t;
typedef struct __mavlink_boot_t
{
uint32_t version; ///< The onboard software version
} mavlink_boot_t;
to name just two...
I want to create a template class such that I can call the said class, which will contain the structure and a few functions and variables.
When I create an instance of the class I want it to create a pointer to the structure (which you will notice is of varying type), therefore I need a constructor and a template to correctly fill in the data types as necessary.
The class (not sure what to call it; template, abstract, interface? who knows lol):
Assuming this is right (is it??) how would I then create an instance of it? My effort of the below isnt correct, it was only a guess since I've not used a template before. Any advice greatly appreciated!
mavlink_heartbeat_t is an instance of the structure __mavlink_heartbeat_t, so I can't create an instance of a non-type.
That's why I thought the type needs to go in the <> in the template, __mavlink_heartbeat_t, and the address of the instance of the structure in the constructor of the class.
Using your method I get the following as the error message:
In file included from /mavlinkSimon.h:3,
from MavlinkTestInternalClass.cpp:16:
handle.h:27: error: expected initializer before 'mlhb'
handle.h:29: error: 'mlhb' was not declared in this scope
I just did a little test on this, very costly, thank you. I'll settle for uint32_t for now, I'll have to thinnk of something clever when I need 64 bit for UNIX time.
howroyd:
I just did a little test on this, very costly, thank you. I'll settle for uint32_t for now, I'll have to thinnk of something clever when I need 64 bit for UNIX time.
Yes you most definitely will need to solve that before 03:14:08 UTC on 19 Jan 2038.
I've been trying to make my code a bit more readable and better, but have messed it up...and cant see my error. Can anyone point me in the right direction please?
Error:
error: request for member 'newData' in 'heartbeat_data', which is of non-class type 'storage<__mavlink_heartbeat_t> ()(mavlink_heartbeat_t)'
Code:
typedef struct __mavlink_heartbeat_t
{
uint8_t type; ///< Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM)
uint8_t autopilot; ///< Type of the Autopilot: 0: Generic, 1: PIXHAWK, 2: SLUGS, 3: Ardupilot (up to 15 types), defined in MAV_AUTOPILOT_TYPE ENUM
uint8_t mavlink_version; ///< MAVLink version
} mavlink_heartbeat_t;
static inline void mavlink_msg_heartbeat_decode(const mavlink_message_t* msg, mavlink_heartbeat_t* heartbeat)
{
#if MAVLINK_NEED_BYTE_SWAP
heartbeat->type = mavlink_msg_heartbeat_get_type(msg);
heartbeat->autopilot = mavlink_msg_heartbeat_get_autopilot(msg);
heartbeat->mavlink_version = mavlink_msg_heartbeat_get_mavlink_version(msg);
#else
memcpy(heartbeat, _MAV_PAYLOAD(msg), 3);
#endif
}
template <typename mavlink_message_type>
class storage {
public:
storage(mavlink_message_type &mavlinkStructure){
msg = mavlinkStructure;
}
private:
mavlink_message_type msg;
void newData(mavlink_message_t* msg, void (*decodeMessage)(const mavlink_message_t*,mavlink_message_type*)){
(*decodeMessage)(msg,this->msg);
}
};
// 0: Heartbeat
storage<__mavlink_heartbeat_t> heartbeat_data(mavlink_heartbeat_t);
void loop(){
mavlink_message_t* msg;
heartbeat_data.newData(msg,mavlink_msg_heartbeat_decode);
}
Go easy on the underscore before variable names, like __mavlink_heartbeat_t. They are supposed to be reserved for implementors (like compiler-writers).
Anyway, I can't see the problem, can you make a complete snippet? For example, show the declaration for mavlink_message_t. I get a lot more errors trying to compile than the one you showed.
All up to the #endif is a snippet of a prewritten library which works and I cant really edit so the underscores arent my doing im afraid.
Also means short of putting the entire lib here i cant really add more code which is a pain, however the lib is solid and works fine.
Everything from the first "template" is my code.
I can only assume, from the error message, that the problem is something to do with the fact there are TWO sets of brackets after the <__mavlink_heartbeat_t> in the error:
storage<__mavlink_heartbeat_t> ()(mavlink_heartbeat_t)
I have no idea why this is, nor what "non-class type" means
I gather you are trying to make an instance of storage templated to __mavlink_heartbeat_t but what are you passing to the constructor? A typename for something that doesn't exist? I'm not sure what this is trying to achieve. You would need to pass an actual thing, not just a type. And in any case I would be cautious about making global declarations like that because of the static initialization order problem.
Hiya, in the library, the structure has an instance created after the close squiggly bracket, called mavlink_heartbeat_t:
typedef struct __mavlink_heartbeat_t
{
uint8_t type; ///< Type of the MAV (quadrotor, helicopter, etc., up to 15 types, defined in MAV_TYPE ENUM)
uint8_t autopilot; ///< Type of the Autopilot: 0: Generic, 1: PIXHAWK, 2: SLUGS, 3: Ardupilot (up to 15 types), defined in MAV_AUTOPILOT_TYPE ENUM
uint8_t mavlink_version; ///< MAVLink version
} mavlink_heartbeat_t;
What I want to do is pass this instance to the constructor (by pointer which i think a structure is by default...like an array?) , hopefully saving memory since I dont need to create my own instance (there are 255 of these structures which is why I'm doing it as a template!).
What is a static initialisation order problem? It needs to be global really since it is a data store for a communications protocol which needs to be accessed by pretty much every class on the system.
A couple of minor points: newData should be public, and using a function pointer on "static inline void mavlink_msg_heartbeat_decode" will defeat the inline (this isn't really an error though as inline is just a hint). Neither of these look like they are the real problem.
I think you might be running into issue 188 which crops up with pointer-to-struct/class functions and still isn't fixed.
Generally, template coding is very complex and error messages often don't refer to the actual line causing the error. The best approach is to only write one line at a time and make sure everything still compiles after adding each line. Start with an empty template with only the parameters and class name, make sure it compiles. Then try to instantiate it, make sure that compiles. Add a default constructor with an empty body, make sure it compiles. Then add a constructor with the right signature but empty body, make sure it compiles. Then modify the instantiation to use the new constuctor, make sure it compiles. etc. etc.
Let's do a simplified version that produces the same message:
typedef struct
{
uint8_t type;
}
foo;
template <typename T> class storage {
public:
// constructor
storage(T &mavlinkStructure){ msg = mavlinkStructure; }
private:
// copy of data
T msg;
// method
void newData(char* msg, void (*decodeMessage)(const char*)){ }
}; // end of class storage
void mavlink_msg_heartbeat_decode (const char *)
{}
// instance of storage
storage<foo> heartbeat_data(foo);
void loop()
{
heartbeat_data.newData("hello", mavlink_msg_heartbeat_decode);
}
void setup () {}
Produces:
sketch_jan11a.cpp: In function 'void loop()':
sketch_jan11a:27: error: request for member 'newData' in 'heartbeat_data', which is of non-class type 'storage<foo> ()(foo)'
That's because foo is a type, not an instance of a type.
Change it to this and the error message changes:
typedef struct
{
uint8_t type;
}
foo;
template <typename T> class storage {
public:
// constructor
storage(T &mavlinkStructure){ msg = mavlinkStructure; }
private:
// copy of data
T msg;
// method
void newData(char* msg, void (*decodeMessage)(const char*)){ }
}; // end of class storage
void mavlink_msg_heartbeat_decode (const char *)
{}
foo bar; // an instance of foo
// instance of storage
storage<foo> heartbeat_data(bar);
void loop()
{
heartbeat_data.newData("hello", mavlink_msg_heartbeat_decode);
}
void setup () {}
Now the error is:
sketch_jan11a.cpp: In function 'void loop()':
sketch_jan11a:15: error: 'void storage<T>::newData(char*, void (*)(const char*)) [with T = foo]' is private
sketch_jan11a:29: error: within this context
That makes sense, newData is private.
Change it to this:
typedef struct
{
uint8_t type;
}
foo;
template <typename T> class storage {
public:
// constructor
storage(T &mavlinkStructure){ msg = mavlinkStructure; }
// method
void newData(char* msg, void (*decodeMessage)(const char*)){ }
private:
// copy of data
T msg;
}; // end of class storage
void mavlink_msg_heartbeat_decode (const char *)
{}
foo bar;
// instance of storage
storage<foo> heartbeat_data(bar);
void loop()
{
heartbeat_data.newData("hello", mavlink_msg_heartbeat_decode);
}
void setup () {}
By the way, I'm not sure how useful it is for the storage class to take a copy of the parameter. This is being passed by value, so you are storing a copy of the original. Maybe that's what you want, but I can't see why offhand. If you want the instance of storage to have the original you need to pass a reference, and store that, like this:
typedef struct
{
uint8_t type;
} foo;
template <typename T> class storage {
public:
// constructor
storage(T &mavlinkStructure): msg (mavlinkStructure) { }
// method
void newData(char* msg, void (*decodeMessage)(const char*)){ }
private:
// data
T & msg;
}; // end of class storage
void mavlink_msg_heartbeat_decode (const char *)
{}
foo bar;
// instance of storage
storage<foo> heartbeat_data(bar);
void loop()
{
heartbeat_data.newData("hello", mavlink_msg_heartbeat_decode);
}
void setup () {}