I already have this class
class sensor : iElectronicParts{
// Some stuff here like methods and properties
};
For accessing all sensors I want to store them in a new object with type of global, so I just coded this class (there's no set method because I already ran into an error)
class global {
public:
sensor getSensors() {
return sensors; // This line throws the error
}
private:
sensor sensors[10];
};
and I got this error message
Compiling sketch...
/tmp/538691267/200119_Growbox/200119_Growbox.ino: In member function
'sensor global::getSensors()':
/tmp/538691267/200119_Growbox/200119_Growbox.ino:335:12: error: could
not convert '((global*)this)->global::sensors' from 'sensor [10]' to
'sensor'
return sensors;
^~~~~~~
exit status 1
I did not instantiated this object yet, I only defined the class. If I replace every type definition of sensor by int it works.
Could someone please tell me what I'm doing wrong / what I have to do to fix this?
You are storing an array of sensor in your class, but GetSensors is trying to return a copy of a single sensor. There's no conversion from an array to a single sensor, so your compiler doesn't know what it needs to do.
The question here is what you want to do: Do you want the whole list, or do you want to get a single sensor.
If You want to return the whole array.
C++ does not support arrays as return types. You will have to return a pointer to the first element in your array.
The code would look like this:
sensor* getSensors() {
return sensors;
}
and you would use it like this, assuming g is an instance of global:
sensor* sensors = g.getSensors();
Serial.print(sensors[3].value);
This code uses what is called array to pointer decay. Callers of your getSensors function will no longer know what the size of the array is, you have to make sure to not go over bounds! As this returns a pointer to the original sensors, any modifications that you do later to the returned pointer will affect the array in the instance of global.
If you want to return a specific sensor
You just need to change your getSensors function to take as an argument the index of the sensor that you care about. It would look like this:
sensor& getSensor(int index) {
return sensors[index];
}
This returns a reference to a specific sensor. As with the pointer case, changes to the returned sensor will affect the original array inside the instance of global (which I assume is the intent)
If you do not want to make modifications to the original array, you should return by value, and omit the & from the return type.
getSensors() function's return type is a mismatch. you should return a sensor object then have to choose one of the sensors[index] or change the return type to sensor pointer. however, I advice to use stl types (you do not have to but it is the best way) #divinas has inform me that no std::array in ardunio so this advice is not applicable:
#include <memory>
#include <array>
class iElectronicParts{};
class sensor : iElectronicParts{
// Some stuff here like methods and properties
};
class global {
public:
std::array<sensor, 10>& getSensors() {
return sensors;
}
private:
std::array<sensor, 10> sensors;
};
int main(){
return 0;
}
Related
I have 2 issues in a template class I'm building. I've included example code below. First question is whether I can coerce the auto type deducted for a templated class. i.e.:
auto p = myvar;
where myvar is T<...>, could I force auto to detect Q<...>? This is simplified. Read on for a more clear explanation.
Edited for clarity: Let me explain what I'm doing. And I'd also like to indicate that this style code is working on a large-scale project perfectly well. I am trying to add some features and functions and in addition to smooth out some of the more awkward behaviors.
The code uses templates to perform work on n-dimensional arrays. The template has a top-level class, and a storage class underneath. Passing the storage class into the top level class allows for a top level class which inherits the storage class. So I start with NDimVar, and I have NDimStor. I end up with
NDimVar<NDimStor>
The class contains NO DATA except for the buffer of data:
class NDimStor<size_t... dimensions> {
int buffer[Size<dimensions...>()]
}
This makes the address of the class == the address of the buffer. This is key to the whole implementation. Is this an incorrect assumption? (I can see this works on my system without any issues, but perhaps this isn't always the case.)
When I create NDimVar<NDimStor<10,10>> I end up with a 10x10 array.
I have functions for getting pieces of the array, for example:
NDimVar<NDimStor<dimensions...>>::RemoveDim & get(int index);
This creates a new 1d array of 10 elements out of the 2d 10x10 array:
NDimVar<NdimStor<10>>
In order to return this as a reference, I use a reinterpret_cast at the location of the data I want. So in this example, get(3) would perform:
return reinterpret_cast<NDimVar≤NDimStor<dimensions...>>::RemoveDim&>(buffer[index * DimensionSumBelow<0>()]);
DimensionSumBelow<0> returns the sum of elements at dimensions 1+, i.e. 10. So &buffer[30] is the address of the referenced 1d NDimVar.
All of this works very well.
The only issue I have is that I would like to add on overlays. For example, be able to return a reference to a new class:
NDimVar<NDimPermute<NDimStor<10,10>,1,0>>
that points to the same original location along with a permutation behavior (swapping dimensions). This also works well. But I would like for:
auto p = myvar.Permute<1,0>()
to create a new copy of myvar with permuted data. This would work if I said:
NDimVar<NDimStor<10,10>> p = myvar.Permute<1,0>().
I feel that there is some auto type deduction stuff I could do in order to coerce the auto type returned, but I'm not sure. I haven't been able to figure it out.
Thanks again,
Nachum
What I want is:
1. Create temporary overlay classes on my storage, e.g. A_top<A_storage> can return a type called A_top<A_overlay<A_storage>> without creating a new object, it just returns a reference to this type. This changes the way the storage is accessed. The problem is upon a call to auto. I don't want this type to be instantiated directly. Can I modify the return to auto to be an original A_top?
#include <iostream>
using namespace std;
class A_storage {
public:
float arr[10];
A_storage () {
}
float & el (int index) {
return arr[index];
}
};
template <typename T> class A_overlay : T {
private:
A_overlay () {
cout << "A_overlay ()" << endl;
}
A_overlay (const A_overlay &) {
cout << "A_overlay (&)" << endl;
}
public:
using T::arr;
float & el (int index) {
return arr[10 - index];
}
};
template <typename T> class A_top;
template <typename T> class A_top : public T {
public:
A_top () {
}
A_top<A_overlay<A_storage>> & get () {
return reinterpret_cast<A_top<A_overlay<A_storage>>&>(*this);
}
};
using A = A_top<A_storage>;
int main (void) {
A a;
auto c = a.get(); // illegal - can i auto type deduce to A_top<A_storage>?
return 0;
}
If a function accepts (A_top<A_storage> &) as a parameter, how can I create a conversion function that can cast A_top<A_overlay<A_storage>>& to A_top<A_storage>& ?
Thanks,
Nachum
First, your design doesn't look right to me, and I'm not sure if the behaviour is actually well-defined or not. (Probably not.)
In any case, the problem is not with auto. The error is caused by the fact that the copy constructor of A_overlay is private, while you need it to copy A_top<A_overlay<A_storage>> returned by a.get() to auto c.
(Note that the auto in this case obviously gets deduced to A_top<A_overlay<A_storage>>, I assume you made a typo when said that it's A_top<A_storage>.)
Also note that A_storage in A_top::get() should be replaced with T, even if it doesn't change anything in your snippet because you only have T == A_storage.
If a function accepts (A_top &) as a parameter, how can I create a conversion function that can cast A_top> to A_top& ?
Ehm, isn't it just this:
return reinterpret_cast<A_top<A_storage>&>(obj);
reinterpret_cast should almost never be used. It essentially remove any compiler validation that the types are related. And doing unrelated cast is essentially undefined behavior as it essentially assume that derived classes are always at offset 0...
It does not make any sense to write such code. It is not maintainable and hard to understand what you are trying to achieve. It look like you want to pretend that your A_top<A_storage> object is a A_top<A_overlay<A_storage>> object instead. If this is what you want to do, then declare A alias as that type.
In your code, it look like you want to invert the indexing so that item at position 10 is returned when you ask item at position 0 and vice versa. Do you really think, that it is obvious from your obfuscated code? Never write such bad code.
Something like
class A_overlay {
public:
float & el (int index) { return arr[10 - index]; }
private:
A_storage arr;
};
would make much more sense than your current code.
No cast needed.
Easy to understand.
Well defined behavior.
You might keep your job.
And obviously, you would update the following line as appropriate:
using A = A_top<A_storage>;
Also, if A_top has no useful purpose, then why not using A_overlay directly? And why are you using template if A_storage is not a template? Do you really want to reuse such mess elsewhere in your code base.
Obviously, your code inheritance does not respect IS-A relationship if your write such code. So it is clearly a bad design!
I am attempting to use std::unordered_set as a hash table to store many CreditCard's. CreditCard and another class CardDatabase are defined as follows:
class CreditCard {
private:
string cardHolder;
unsigned long long cardNumber;
int limit;
int balance;
public:
CreditCard(string in_cardHolder, string in_cardNumber, int in_limit) {
cardHolder = in_cardHolder;
cardNumber = stoll(in_cardNumber);
limit = in_limit;
balance = 0;
}
void ChangeBalance(int amount) const {
balance += amount; // SECOND ERROR
}
};
class CardDatabase {
private:
unordered_set<CreditCard> cards;
unordered_set<CreditCard>::iterator iter;
public:
CardDatabase() { }
void AddCard(cardHolder, cardNumber, int limit) {
CreditCard tempCard = CreditCard(cardHolder, cardNumber, limit);
cards.insert(tempCard);
}
void Charge(string cardHolder, int chargeAmount) {
iter = cards.find(cardHolder);
iter->ChangeBalance(chargeAmount); // FIRST ERROR
}
}
Initially I was getting the following compile error at FIRST ERROR: Member function 'ChangeBalance' not viable: 'this' argument has type 'const CreditCard', but function is not marked const. So, I added the "const" to the ChangeBalance function. However, after doing that I get the following compile error at SECOND ERROR: Cannot assign to non-static member within const member function 'ChangeBalance'.
Is there any way to fix this error without changing balance to a static variable? It is obviously important that the balance be different for each CreditCard instance.
Any help is appreciated.
EDIT:
Thank you all for your quick answers. I feel I should clarify something. I already added the proper hash functionality elsewhere in my code:
namespace std {
template <>
struct hash<CreditCard> {
size_t operator()(const CreditCard& cc) const
{
return hash<string>()(cc.GetCardHolder());
}
}
}
Also, the code I posted initially pasted is from a much larger code base and I didn't delete all the necessary namespacing stuff at first before posting the question. My apologies for the confusion.
Members of an unordered_set are constant, and cannot be changed once they're in the unordered_set, by default. You are trying to change the objects in the set, and the compiler is properly telling you that you can't do this.
The only possible way to do this correctly (explained only for educational purposes, because this is bad class design):
Explicitly declare the individual fields that can be modified in this manner as mutable.
Use a custom hash function with your unordered_set, and the hash function must exclude the value of mutable fields from the value of the calculated hash.
Otherwise, modifying the contents of the object in the set obviously changes its hash value, which will result in undefined behavior.
Again, this is explained for informational purposes only. This is not a good class design.
The clean way to do this would be to assign a unique identifier to each CreditCard (you know, like a credit card number?), and use an ordinary std::map, to look up CreditCards by their number.
It's not appropriate for ChangeBalance to have const semantics. By the very nature of it's name, you're modifying the object. Make the function non-const.
void ChangeBalance(int amount) {
balance += amount;
}
The other problem is that you didn't call your function correctly. You should instead do this:
iter->ChangeBalance(chargeAmount);
I will mention there are cases where you want to modify values in a const object, and there is a mutable type modifier for that. Do not use it to solve your current error, however!
void ChangeBalance(int amount) should not be const - it is changing the object.
The problem is before in the iterator: cards.find returns a const object, so you are not allowed to change it.
A way to resolve that is to make your cards set a set of pointers to cards, not of cards; or to use another way to find the matching card
Playing fast and loose with the C++ syntax in that thar code, Hoss. Plenty of errors wait around the corner
First Error:
iter->CreditCard::ChangeBalance(chargeAmount);
should be
iter->ChangeBalance(chargeAmount);
Straight-up bad syntax that likely results from flailing around because of the errors resulting from unordered_set having no idea how to hash a CreditCard. Give this a read: How do I use unordered_set? That said, unordered_set is probably not the right solution for this job. std::map<std::string, CreditCard> looks more on point.
Using the wrong solution to fix the above problem lead to the
Second Error:
void ChangeBalance(int amount) const
const on a method means the method cannot change the state of the object. in ChangeBalance balance += amount; attempts to change the state of the object by updating a member variable.
In addition, the compiler is going to HATE the CreditCard:: in this:
CreditCard::CreditCard(string in_cardHolder, string in_cardNumber, int in_limit) {
cardHolder = in_cardHolder;
cardNumber = stoll(in_cardNumber);
limit = in_limit;
balance = 0;
}
Another solution is to make the "balance" as a static member.
class CreditCard {
private:
string cardHolder;
unsigned long long cardNumber;
int limit;
static int balance;
....
}
And then initialize it in cpp file
int CreditCard::balance = 0;
This code may not be very secure. But this can be one of the workaround.
I have 3 classes. DrawGameComp' and 'GameComp' where 'GameComp' is the base class of 'DrawGameComp'. I have an array of pointers in Game class which is the controlling class. '
GameComp * components[]; From the main I have to create a dynamic instance of Game and store add new objects of GameComp and DrawGameComp to the array of pointers of type GameComp.
Game Game1(2);
Game1.Add(new GameComponent);
Game1.Add(new DrawableGameComponent);
I'v done this part in the main. Because from the main I have to invoke Add passing object as the parameter. When i store these objects I also want assign an id of 1 to the first object and an id of 2 to the second object. How can i include that too.
The Add() function of my Game class is as follows
void Game::Add(GameComponent*)
{
components[0]=GameComp;
componentCount++;
}
but it give me error. I have tried so hard. But I couldn't. Also how do I invoke the Display() member function of these objects in the Array? is it this way?
components[0]->Display();
The Add method should look like:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
Make sure you zero out componentCount in the constructor.
Using the array:
components[i]->DoSomething();
1) You probably meant to write the following:
void Game::Add(GameComponent* comp)
{
components[componentCount++] = comp;
}
2) components[0]->Display() will work, if display is a member function of GameComponent class.
I'm a newbie to arduino and programming.
I've included a library inside my own library in arduino, but first library contains a function which has a pointer function as a parameter. It is an interrupt service routine(ISR) but I need to call a function in my cpp file when interrupt is occurred. So I need to pass the pointer of that function to the first library code. It works well when I use it in .ino file, I can pass it like,
attachInterrupt(functionISR_name);
but when I use it in .cpp file, I get errors. my function is like,
void velocity::functionISR_name(){
//some code
}
but how can I pass the pointer of this function to the first library function? I tried this way but got errors,
attachInterrupt(velocity::functionISR_name);
You cannot pass a method to a function which expects a function, unless you define it static.
write it static :
static void velocity::functionISR_name()
and
attachInterrupt(&velocity::functionISR_name);
Unfortunately the static method is not bound to a specific instance any more. You should use it only together with a singleton. On Arduino you should write the class like shown below in the code snipped:
class velocity
{
static velocity *pThisSingelton;
public:
velocity()
{
pThisSingelton=this;
}
static void functionISR_name()
{
pThisSingelton->CallWhatEverMethodYouNeeded();
// Do whatever needed.
}
// … Your methods
};
velocity *velocity::pThisSingelton;
velocity YourOneAndOnlyInstanceOfThisClass;
void setup()
{
attachInterrupt(&velocity::functionISR_name);
// …other stuff…
}
This looks ugly, but in my opinion it is totally okay with Arduino as the opportunities are very limited on such a system.
Thinking again over it, I would personal go for the approach Sorin mentioned in his answer above. That would be more like that:
class velocity
{
public:
velocity()
{
}
static void functionISR_name()
{
// Do whatever needed.
}
// … Your methods
};
velocity YourOneAndOnlyInstanceOfThisClass;
void functionISR_name_delegation()
{
YourOneAndOnlyInstanceOfThisClass.functionISR_name();
}
void setup()
{
attachInterrupt(functionISR_name_delegation);
// …other stuff…
}
It would also save you some bytes for the pointer you need in the first example.
As a site note: For the future, please post the exact code (for e.g. attachInterrupt needs more parameter) and copy&paste the error messages. Usually error are exact at a place you do not suspect. This question was an exception. Normally I and other would ask for better specification.
You pass a pointer to the function but the function is a class member. Likely the call will be invalid because the this pointer will be garbage(may compile fine but will throw strange errors at runtime).
You need to define a plain vanilla function, outside of any class, and use that.
If you don't have a very complex project you can get away with having a global pointer to the class instance you should use and just delegate the call in your new function.
If you want to do thing the right way you need some mechanism to get the instance pointer I talked about above. Usually this involves either a singleton or some factory pattern.
Example:
class Foo {
void method() {
x = 5;
}
int x;
}
Having a callback on method will crash because you have an invalid pointer for this so x=5 will write 5 somewhere randomly in memory.
What you need is somehting like:
static Foo* foo_instance; // Initialized somewhere else.
void method_delegator() {
foo_instance->method();
}
Now you can pass method_delegator to the function. It will work because you now also pass foo_instance for this pointer.
I have class Student (studentOwner) and class Section.
Here is my class Student:
class Student {
vector<Section*> enrolledSections;
public:
vector<Section*> getEnrolledSections() const { return enrolledSections; }
}
So, when I get vector<Section*> and assign to another vector, I will meet error. I'm using Microsoft Visual Studio.
// first example: no error, if take size of vector
int a = studentOwner->getEnrolledSections().size();
// second example: error, when only take its vector and assign again
// Error: no suitable user-define conversion from "std::vector<error-type" ....
vector<Section*> enrolled = studentOwner->getEnrolledSections();
// third example: error when take this vector and assign to reference of same type
// Error: initial value of reference to non-const value must be lvalue
vector<Section*>& enrolled = studentOwner->getEnrolledSections();
Full error at second example is:
Error: no suitable user-define conversion from "std::vector<error-type", std::alocator<<error-type> *>> "to " std::vector<Section*, std::allocator<Section*>>" exists
In many class of my project, I cannot do line two and line three and received same error. I cannot explain by myself. Please teach me at this point.
Thanks :)
Usually if you see error-type in MSVC errors, it's a result of a forward declared type that wasn't included in time for that compilation unit. For example,
// Course.h
class Student;
class Course {
[...]
public:
Student* getStudent();
}
// Course.cpp
#include "Course.h"
Student* Course::getStudent()
{
return new Student("Name"); //< Whoops, we never included Student.h!
}
In the comments you indicate a circular include dependency. As #Daniel Castro noted, you should forward declare in your header files to avoid the circular includes, then include the needed header files in your .cpp files (note the forward declaration class Student; above if you're not familiar).
As an aside, I would also note some design issues with your example. Returning std::vector<Section*> doesn't tell much about who owns what. If I get a std::vector by value from a function, the convention is that I now own the vector and its contents. If I own something, then I'm responsible for deleting it. Without seeing your actual implementation, most coders would be surprised to learn they shouldn't delete the contents of the vector. I would suggest either returning the vector by const& (eg, const vector<Section*>&) which prevents client code from manipulating the vector (so clients don't own it), or using std::shared_ptr to manage a shared ownership scheme of your Section objects:
class Student {
vector<shared_ptr<Section>> enrolledSections_;
public:
vector<shared_ptr<Section>> getEnrolledSections() const { return enrolledSections_; }
}
Now it's clear who owns what. More than you were asking for, but hopefully it helps.
you need to return the vector as a reference, otherwise the vector is copied on return. Also your function is const, so you have to return the vector as const too.
class Student
{
std::vector<Section*> enrolledSections;
public:
const std::vector<Section*> &getEnrolledSections() const { return enrolledSections; }
}
now you should be able to
const std::vector<Section*>& enrolled = studentOwner->getEnrolledSections();