I’m able to produce a compilable piece of code that will pass structs to functions, however my code just falls apart when i’m trying to use ‘pass by value’.
I’ve looked at how to use the same formatted struct across multiple files, but i’m not sure if it’s any different when passing functions by value?
Note: this is written in the arduino IDE in C++
my code for passing by address follows:
passingStructs.ino
#include "a.h"
#include "b.h"
myStruct volatile structure1;
void setup() {
}
void loop() {
structure1.foo = 7;
structure1.bar = 11;
int lower = minusData(&structure1);
int higher = addData(&structure1);
}
a.h:
#include "b.h"
#ifndef __a_h
#define __a_h
//prototype functions
int addData(struct myStruct *structureC);
#endif //__a_h
a.cpp:
#include "a.h"
#include "b.h"
int addData(struct myStruct *structureC) {
int x = structureC->foo;
int y = structureC->bar;
return (x + y);
}
b.h:
#ifndef __b_h
#define __b_h
//Define structure
typedef struct myStruct {
int foo;
int bar;
};
//Prototype functions
int minusData(struct myStruct *structureC);
#endif //__b_h
b.cpp:
#include "b.h"
myStruct structureC;
int minusData(struct myStruct *structureC) {
int x = structureC->foo;
int y = structureC->bar;
return (x - y);
}
however if i use
int higher = addData(structure1);
in the .ino file and
int addData(struct myStruct structureC) {
int x = structureC.foo;
int y = structureC.bar;
return (x + y);
}
in the a.cpp file with the same prototype in the header file, the compiler rejects the code saying
no matching function for call to ‘myStruct::myStruct(volatile myStruct&)’
any ideas?
C++ will generate default constructors and a copy operator for structs and classes.
For your myStruct these implicit functions would be:
struct myStruct {
myStruct() {} // <-- implicit default constructor.
myStruct(const myStruct& other) // <-- implicit copy contructor
{
foo = other.foo;
bar = other.bar;
}
myStruct& operator = (const myStruct& other) // <-- implicit copy operator
{
foo = other.foo;
bar = other.bar;
return *this;
}
int foo;
int bar;
};
Note that the copy constructor and operator expect a const myStruct& parameter. The volatile keyword in your definition of myStruct volatile structure1; prevents parameter matching.
You'd have to explicitly declare a copy operator and/or constructor that accept a const volatile myStruct& to make your code compile.
volatile data needs special handling by the compiler's optimizer. That's why the volatile keyword is important here. You should really consider whether your data really needs this qualifier. On the Arduino, there is only one case where this keyword is needed, that is when the data is modified by an interrupt routine.
Alternatively, you can define functions that accept a volatile reference or pointer to data:
struct MyStruct // I suggest you use this syntax for declarting structures
{ // So you don't ghave to repeat the struct keyword everywhere.
myStruct(const myStruct& other)
{
foo = other.foo;
bar = other.bar;
}
myStruct(const volatile myStruct& other)
{
foo = other.foo;
bar = other.bar;
}
int foo, bar;
};
int addData(volatile const myStruct* structureC)
{
return structureC->foo + structureC->bar;
}
int addData(volatile const myStruct& structureC)
{
return structureC.foo + structureC.bar;
}
int addDataByCopy(myStruct structureC)
{
return structureC.foo + structureC.bar;
}
// ...
volatile myStruct my;
void loop()
{
my.foo = 1;
my.bar = 1;
int x = addData(my); // by const reference.
// or
int y = addData(&my); // by pointer.
// or
int z = addDataByCopy(my); // by copy
}
Related
I have the following code:
class example {
int x;
inline void operator=(int value) { x = value; }
};
int main() {
example foo { 100 };
int bar = foo;
}
The int bar = foo; obviously doesn't work, because I'm trying to assign a variable of type example to a variable of type int.
Is it possible to retrieve the x variable without using a getter function and without using operator.? If so, is it still possible to do purely by code inside the struct, and keeping the int bar = foo; as is?
Add a conversion function to allow implicit conversion
struct example {
int x;
inline void operator=(int value) { x = value; }
operator int() const
{
return x;
}
};
int main() {
example foo { 100 };
int bar = foo;
}
I'm working on a small assignment for a class. I need to overload the '+' operator to add together two private member variables of a class object. The class objects are pointed to by an array of class pointers. I'm not quite sure where to start debugging, but my operator overload function causes the program to crash.
Here is main.cpp (ignore printObjects and freeObjects for now).
#include <iostream>
#include "Foo.h"
using namespace std;
void createObjects(Foo* fooArr[3], Foo* newFoo);
void printObjects(Foo* fooArr[3], Foo newFoo);
void freeObjects(Foo* fooArr[3], Foo newFoo);
int main()
{
Foo *fooArr[3] = { 0 };
Foo *newFoo = 0;
createObjects(&fooArr[3], newFoo);
Foo f1 = *(fooArr[1]) + *(fooArr[2]);
f1.outputX();
}
void createObjects(Foo* fooArr[3], Foo* newFoo)
{
for (int i = 0; i < 3; i++)
{
newFoo = new Foo(i+1);
fooArr[i] = newFoo;
}
}
Here is Foo.h:
using namespace std;
class Foo
{
private:
int x;
public:
Foo();
Foo(int);
void setX(int);
const int getX();
void outputX();
Foo operator+(const Foo&) const;
};
And finally here is foo.cpp:
#include <iostream>
using namespace std;
#include "Foo.h"
Foo::Foo(int x_)
{
x = x_;
}
void Foo::setX(int x_)
{
x = x_;
}
const int Foo::getX()
{
return x;
}
void Foo::outputX()
{
cout << x << endl;
}
Foo Foo::operator+(const Foo& f2) const
{
Foo f3(0);
f3.x = x + f2.x;
return f3.x;
}
The program crashes (segFault), right after calling the operator+ overload function. Now I know this means I am trying to access memory that the program doesn't actually have access to. However, I just don't know how to craft the operator overload statement to work with the function call:
Foo f1 = *(fooArr[1]) + *(fooArr[2]);
Any help would be much appreciated.
Thanks!
How can I enable explicit casting from, lets say int, to a user defined class Foo?
I made a conversion constructor from int to Foo, but is that it? I could overload a cast operator from Foo to int, but that is not what I'm looking for.
Is there a way to enable this piece of code?
int i = 5;
Foo foo = (Foo)i;
Something like this:
struct Foo {
explicit Foo(int x) : s(x) { }
int s;
};
int main() {
int i = 5;
Foo foo =(Foo)i;
}
Read about converting constructor.
If you won't set constructor as explicit, it allows you to convert type (which constuctor accepts) to a (newly constructed) class instance.
Here is the example
#include <iostream>
template<typename T>
class Foo
{
private:
T m_t;
public:
Foo(T t) : m_t(t) {}
};
int main()
{
int i = 0;
Foo<int> intFoo = i;
double d = 0.0;
Foo<double> doubleFoo = d;
}
You need a constructor which accecpts an int
class Foo {
public:
Foo (int pInt) {
....
}
Foo (double pDouble) {
....
}
int i = 5;
Foo foo(i); // explicit constructors
Foo foo2(27);
Foo foo3(2.9);
Foo foo4 = i; // implicit constructors
Foo foo5 = 27;
Foo foo6 = 2.1;
I would like the compiler to enforce const-ness of an lvalue (non-reference) but don't know if this is possible in C++. An example:
int foo() { return 5; }
int main() {
// Is there anything I can add to the declaration of foo()
// that would make the following cause a compile-error?
int a = foo();
// Whereas this compiles fine.
const int a = foo();
}
This is not really possible with something like an int because you need to give access to read the int and if they can read the int then they can copy it into a non-const int.
But from your comments it sounds like what you have in reality is not an int but a more complex user defined type, some sort of container perhaps. You can easily create an immutable container. This container could be a wrapper, or alternative implementation of your existing container. It then doesn't matter if the caller uses a const or non-const variable it is still immutable.
class MyClass {
std::vector<int> data;
public:
MyClass(size_t size) : data(size) {}
int& operator[](size_t index) { return data[index]; }
int operator[](size_t index) const { return data[index]; }
size_t size() const { return data.size(); }
};
class MyClassImmutable {
MyClass mc;
public:
MyClassImmutable(MyClass&& mc) : mc(std::move(mc)){}
int operator[](size_t index) const { return mc[index]; }
size_t size() const { return mc.size(); }
const MyClass& get() const { return mc; }
};
MyClassImmutable foo() {
MyClass mc(100);
mc[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
MyClassImmutable mci = foo();
std::cout << mci[10] << "\n"; // Can read individual values
//mci[10] = 4; // Error immutable
func(mc.get()); // call function taking a const MyClass&
}
Live demo.
Of course there is nothing to stop the caller from copying each and every value from your immutable container and inserting them into a mutable container.
Edit: An alternative approach might be to return a smart pointer-to-const. The only downside is you have to pay for a dynamic memory allocation:
std::unique_ptr<const MyClass> foo() {
auto mc = std::make_unique<MyClass>(100);
(*mc)[10] = 3;
return mc;
}
void func(const MyClass& mc);
int main() {
auto mc = foo();
std::cout << (*mc)[10] << "\n"; // Can read individual values
//(*mc)[10] = 4; // Error const
func(*mc); // can pass to a function taking a const MyClass&
}
It's not possible. foo() has no way of knowing about the type of the left hand side of the assignment, because when the assignment itself happens, foo() is already evaluated. The best you could hope for is to change the return value, to try and cause a type-based error on the initialization:
#include <type_traits>
struct my_int {
const int m;
template<typename T, typename std::enable_if<std::is_const<T>::value, T>::type* = nullptr>
constexpr operator T() const {return m;}
};
constexpr my_int foo() { return {5};}
int main() {
const int a = foo();
int b = foo();
}
Live example
But this will also not work, because the typename in the template will never be substitued by a const-qualified type (in this specific case, it will be int for both lines in main()).
As the following is possible
const int x = 4;
int y = x;
the C++ language will not provide such a mechanism.
Remains making a int const by a macro mechanism.
#define int_const_foo(var) const int var = ___foo()
int_const_foo(a);
Drawback: foo cannot be hidden, and the syntax is no longer C style.
Lets assume we have two classes
struct A
{
int x = 1;
};
struct B
{
int y = 2;
};
I want to have template that will return value of member (in a case of A I want to return value of "x", in case of B I want to return value of "y").
Example call:
const auto myVariable = f<A>();
or
A a;
const auto myVariable = f<A>(a);
I don't want to have 2 template specializations - ideally it would be one template with some kind of "if statement", but maybe it is not possible?
It may be written with C++11 (but not with C++14).
Generally how you are using templates when you have such problems - quite big template and only in one or two places you need to take values from different members - which may be deduced based of type of that variable.
PROBLEM: unnecessary it is not allowed to modify classes A and B
Why use templates at all?
int f(const A& a) { return a.x; }
int f(const B& b) { return b.y; }
Just in case you ask for the template because you want to switch between A and B at compile time...and you have a reason not to simply typedef A or B directly...
struct A
{
int x;
};
struct B
{
int y;
};
struct A1 : public A { int Get() const { return x; } };
struct B1 : public B { int Get() const { return y; } };
// Begin possible shortcut avoiding the template below:
#ifdef USE_A
typedef A1 Bar;
#endif
#ifdef USE_B
typedef B1 Bar;
#endif
// End possible shortcut.
template <class _Base>
struct CompileTimeAOrB
: public _Base
{
int Get() const
{
return _Base::Get();
}
};
#define USE_A
//#define USE_B
#ifdef USE_A
typedef CompileTimeAOrB<A1> Foo;
#endif
#ifdef USE_B
typedef CompileTimeAOrB<B1> Foo;
#endif
EDIT: Since A and B cannot be changed, introduced A1, B1 ;)
#include <iostream>
struct A
{
int value;
A() : value(2) {}
};
struct B
{
int value;
B() : value(4) {}
};
template <typename T>
int GetValue(T t)
{
return t.value;
}
int main()
{
A a;
B b;
std::cout << GetValue(a) << std::endl;
std::cout << GetValue(b) << std::endl;
return 0;
}
In order for it to work, you'd need to have the same variable or function named declared in each class you wanted this to work with.