How to accept both modifiable and non-modifiable arguments? - c++

I have a debugging macro where I give it a float reference, and expect it to modify that variable sometimes, if it can.
#define probe(x) implProbe(#x##GETLINE, (x))
void implProbe(const char * loc, float & x){
// this signature is a place holder
...
x = 4.f;
}
However, I would also like to use the same macro for temporary variables or literals such as probe(1 + 2) or probe(x + y). The macro wouldn't need to have the same effect in those cases, I don't expect to see an output from it, I only want it to not break.
float var = 0.f;
probe(var);
// var == 4.f
var = 0.f;
probe(var + 2.f); // this should be legal
// var == 0.f (didn't change)
probe(1.f); // this should be legal
Is there a way to accomplish this?

Implement two overloaded functions.
void implProbe(const char * loc, float & x){
...
x = 4.f;
}
void implProbe(const char * loc, const float & x){
...
}

Related

Passing a function to another function in C++ where the number of arguments can be different

I am working on a problem in C++17 where I am building a root solver that allows the user to pass a user-defined function to the root-solving function. An example of the class is shown below for the .cpp file and the prototype is in the .hpp file.
// root.cpp
double RootSolver::newton(double guess, double right_side,
double (*func)(double),
double unc, int iter)
/**
Finds a specific root of a function using the Newton iteration
method
#param guess An initial guess for the value of the root
#param right_side The value of the right side of the
function.
#param func The function for which the root will be
determined
#param unc The uncertainty or tolerance in the accepted
solution. Defaulted to 0.001
#param iter The number of iterations to try before the
function fails. Defaulted to 150.
#return root
*/
{
double x1, x2, x3, y1, y2, slope;
x1 = guess;
x2 = x1 + 0.0000001;
for (int i = 0; i < iter; i++)
{
y1 = func(x1) - right_side;
y2 = func(x2) - right_side;
slope = (y2 - y1) / (x2 - x1);
x3 = x1 - (y1 / slope);
if (func(x3) - right_side <= unc and
func(x3) - right_side >= -unc) return x3;
x1 = x3;
x2 = x1 + 0.0000001;
}
exit_program(iter);
}
// ================================================================
// RootSolver PRIVATE FUNCTIONS
[[noreturn]] void RootSolver::exit_program(int iter)
{
std::string one("Function did not converge within ");
std::string two(" iterations");
std::cout << one << iter << two << std::endl;
exit (EXIT_FAILURE);
}
The main file looks like this;
double func1(double x);
double func2(double x, double a, double b);
int main() {
RootSolver q;
double guess = 2.0;
double right_side = 0.0;
// This function works fine
result = q.newton(guess, right_side, func1)
// - Not sure how to reformat RootSolver.newton so
I can pass it func1 as well as func2 so it can
accept the arguments a and b
return 0;
}
double func1(double x)
{
return pow(x, 6) - x - 1.0;
}
double func2(double x)
{
return pow(x, 6) - a * x - b * 1.0;
}
The code shown above works great for func1, since x is the only argument; however, I am not sure how to reformat the RootSolver.newton function so it will take func1 with no arguments except x and accept func2 and the arguments a and b. Does anyone know how I can pass arguments to the function newton such that it is not hardcoded for a specific input function?
Based on the loose description, it sounds like a caller-side lambda solves your problem:
result = q.newton(guess, right_side, [](double x) {
return func2(x, 0, 0); // Replace 0s with values of a and b.
});
This lambda is converted to double(*)(double) as needed. Note that this will not work if you need to capture something because function pointers can't store additional state. There are two easy ways to handle that.
Make a template (and put the definition in the header):
template<typename F>
// requires std::is_invocable_r_v<double, F, double> // C++20 constraint option A
// requires requires(F f, double x) { f(x) -> double; } // C++20 constraint option B - can be extracted into a concept
double RootSolver::newton(double guess, double right_side,
F func,
double unc, int iter)
Use std::function at the cost of some performance when calling it:
double RootSolver::newton(double guess, double right_side,
const std::function<double(double)>& func,
double unc, int iter)
You can use function overloading in this case.
You can pass function name and x, a and b as parameters in overloaded versions, somewhat like this (I am just considering func, x, a and b for now, but you get the idea):
1) Overloaded version 1 that accepts func1 and its 2-parameters
double newton(...<other parameters>..., double (*func)(double), double x)
2) Overloaded version 2 that accepts func2 and its 3-parameters
double newton(...<other parameters>..., double (*func)(double, double, double), double x, double a, double b)
Now when you wish to call with func1, use:
newton(...., func1, x)
when you wish to call with func2, use:
newton(..., func2, x, a, b)

Return my struct as an array in C++, OPENGL

I have a problem with my function. I can't seem to make it return an array of a struct.
Here is the MyApp.h header file:
struct Vertex
{
glm::vec3 p;
glm::vec3 c;
};
class CMyApp
{
public:
CMyApp(void);
~CMyApp(void);
Vertex[] DrawCircle(int cx, int cy);
...
It underlines the DrawCircle and "expects a ';'".
Here is the MyApp.cpp (Of course, header included):
Vertex[] CMyApp::DrawCircle(int cx, int cy) {
Vertex result[42];
result[0] = { glm::vec3((float)cx, (float)cy, 0.0), glm::normalize(glm::vec3(0, 0, 1)) };
for (int ii = 1; ii < 21; ii++) {
float theta = 2.0f * 3.1415926f * float(ii) / float(20);
float x = 0.5 * cosf(theta);
float y = 0.5 * sinf(theta);
result[ii].p = glm::vec3(x, y, 0.0);
result[ii].c = glm::normalize(result[ii].p);
}
result[21] = { glm::vec3((float)cx, (float)cy, 2.0), glm::normalize(glm::vec3(0, 0, 1.0)) };
for (int ii = 22; ii < 42; ii++) {
float theta = 2.0f * 3.1415926f * float(ii) / float(20);
float x = 0.5 * cosf(theta);
float y = 0.5 * sinf(theta);
result[ii].p = glm::vec3(x, y, 2.0);
result[ii].c = glm::normalize(result[ii].p);
}
return result;
}
Same underline here under the function name's DrawCircle for expected ";".
If I remove the array marks then the only error is the return statement. I want to return as an array tho.
Thanks for help in advance.
You cannot return a local array. Such an array is allocated on the stack; when the function returns, all its content is available for other stack variables. If you use it after the call, its content is likely to be corrupted.
So
Vertex[] CMyApp::DrawCircle(int cx, int cy) {
Vertex result[42];
return result;
}
is undefined behavior for the compiler.
You should use a vector instead. Its move constructor makes it efficient for returning many results organized as an array.
std::vector<Vertex> CMyApp::DrawCircle(int cx, int cy) {
std::vector<Vertex> result;
result.reserve(42);
// same content than your original code.
...
return result;
}
Note that if you declare
class CMyApp
{
public:
CMyApp(void);
~CMyApp(void);
typedef Vertex ArrayOfVertices[];
ArrayOfVertices DrawCircle(int cx, int cy);
};
You obtain the error message:
error: ‘DrawCircle’ declared as function returning an array
ArrayOfVertices DrawCircle(int cx, int cy);
I want to return as an array tho.
You can't. C and C++ don't allow it. What you can do in C++ is returning a std::vector which you should use instead of plain arrays anyway.

operator overload. q = q1+q2, q1 being modified but I want q1 and q2 to be intact

I learnt operator overloading like 1 or 2 weeks ago and I think I know how it works but I'm trying to overload the operator + so it returns a new CCuaternion which is working well but
CCuaternion(float w, float x, float y, float z) {
this->w = w;
this->x = x;
this->y = y;
this->z = z;
} //Ccuaternion constructor at Ccuaternion.h
CCuaternion operator + (CCuaternion &q2); // at CCuaternion.h
CCuaternion CCuaternion::operator + (CCuaternion &q2){ // at Ccuaternion.cpp
CCuaternion suma;
suma.setW(w += q2.getW());
suma.setX(x += q2.getX());
suma.setY(y += q2.getY());
suma.setZ(z += q2.getZ());
return suma; }
In my main I have an object CCuaternion called qsuma which receives the CCuaternion that the overload is returning. It looks like this:
q1 = CCuaternion(0, 1, 0, 1); // at main.cpp
q2 = CCuaternion(1, 0, 0, 1);
qsuma = (q1+q2);
As supposed to, qsuma ends up with the values 1, 1, 0, 2.
q2 stays the same but q1 ends up with the same value as qsuma.
The preferred way to overload addition operators is like this:
CCuaternion & CCuaternion::operator += (CCuaternion const &q2)
{
w += q2.w;
x += q2.x;
y += q2.y;
z += q2.z;
return *this;
}
and this is a non-member function:
CCuaternion operator + (CCuaternion q1, CCuaternion const &q2)
{
return q1 += q2;
}
This keeps your code very simple and intuitive and also lets people use += on your class.
Your are doing it the wrong way:
CCuaternion operator + (const CCuaternion& q2) const; // at CCuaternion.h
CCuaternion CCuaternion::operator + (const CCuaternion &q2) const { // at Ccuaternion.cpp
return CCuaternion(w + q2.w,
x + q2.x,
y + q2.y,
z + q2.z);
}
You were using +=
See the const modifier for q2
Update
In C++98, const means logically constant, the programmer promises the state of the argument will no be changed inside the function.
(Note: I changed the signature adding const at the end of the declaration so this can be constant too)
So, Why you need const?
It's a good practice: if the function is not going to change the value then it's just more polite to use const.
You may need it in another context, I mean, you must to be able to apply this operator not only on variables, but also on constants.

Why does calling a method on a pointer to an object have different behaviour from calling the method on the object itself?

I have some code where I have a pointer to an object. I call a method on that pointer but the behaviour of the method is wrong in this case. I tried calling a method on the object itself and this actually gives the desired behaviour of the method.
Why does this cause different behaviour?
Also is there a way of assigning an object to a new variable without using pointers because I want the behaviour for the method called on the object itself?
Thanks.
EDIT:
Hopefully a sufficient example:
In a Robot class:
std::vector<ProjectOne::R_ID> Robot::positions;
int Robot::ID = -1;
Robot::Robot(double x, double y)
{
++ID;
robot_ID = ID;
initialX = x;
initialY = y;
// Placeholder. Doesn't actually get used properly atm.
fWidth = 0.35;
px = x;
py = y;
ProjectOne::R_ID msg;
msg.R_ID = robot_ID;
msg.x = x;
msg.y = y;
positions.push_back(msg);
string robotOdom = "robot_" + int2str(robot_ID) + "/odom";
string robotVel = "robot_" + int2str(robot_ID) + "/cmd_vel";
RobotOdometry_sub = n.subscribe<nav_msgs::Odometry>(robotOdom,1000,&Robot::ReceiveOdometry,this);
RobotVelocity_pub = n.advertise<geometry_msgs::Twist>(robotVel,1000);
ros::spinOnce();
}
void Robot::ReceiveOdometry(nav_msgs::Odometry msg)
{
//This is the call back function to process odometry messages coming from Stage.
px = initialX + msg.pose.pose.position.x;
py = initialY + msg.pose.pose.position.y;
ptheta = angles::normalize_angle_positive(asin(msg.pose.pose.orientation.z) * 2);
}
int Robot::selectLeader()
{
int leader_ID = robot_ID;
double lowestDistance = 9999999999.9;
for (unsigned int i=0;i<positions.size();i++)
{
double distance = calculateDistance(positions[i].x, positions[i].y, 0.0, 0.0);
if (distance < lowestDistance && distance != 0.0)
{
leader_ID = positions[i].R_ID;
lowestDistance = distance;
}
}
ROS_INFO("leader is: %d", leader_ID);
return leader_ID;
}
double Robot::calculateDistance(double x1, double y1, double x2, double y2)
{
double deltax = x2 - x1;
double deltay = y2 - y1;
double distanceBetween2 = pow(deltax, 2) + pow(deltay, 2);
double distanceBetween = sqrt(distanceBetween2);
return distanceBetween;
}
double Robot::calculateHeadingChange(double x, double y)
{
double deltax = x - px;
double deltay = y - py;
double angleBetween = atan2(deltay, deltax);
double headingChange = angleBetween - ptheta;
return headingChange;
}
void Robot::align(double x, double y)
{
ros::Rate loop_rate(10);
double headingChange = calculateHeadingChange(x, y);
double angularv = headingChange / 5;
double heading = ptheta + headingChange;
while (heading > 2 * M_PI)
{
heading -= 2 * M_PI;
}
while (heading < 0)
{
heading += 2 * M_PI;
}
geometry_msgs::Twist msg;
msg.linear.x = 0;
msg.angular.z = angularv;
while (ros::ok())
{
RobotVelocity_pub.publish(msg);
ros::spinOnce();
ROS_INFO("Heading Change %f pthea is %f %f %f", headingChange, ptheta, px, py);
loop_rate.sleep();
}
}
And this is the code that calls the method:
int main(int argc, char **argv) {
ros::init(argc, argv, "robotNode");
Robot r1(5,10);
Robot r2(15,20);
Robot r3(10,30);
Robot r4(25,16);
Robot r5(5,28);
Robot r6(10,10);
Robot Group[6] = {r1, r2, r3, r4 ,r5, r6};
std::vector<Robot> Herd;
int leaderID = r1.selectLeader();
Robot * leader;
for (int i=0;i<6;i++) {
if (Group[i].robot_ID == leaderID) {
leader = &Group[i];
} else {
Herd.push_back(Group[i]);
}
}
(*leader).align(0.0, 0.0); //Problem area
}
The problem is that your array (Group) and vector (Herd) both contain copies of the automatic objects (r1 and friends); so anything you do to those will not affect the originals.
You probably want to work with pointers instead:
Robot * Group[6] = {&r1, &r2, &r3, &r4, &r5, &r6};
std::vector<Robot*> Herd;
In general, you need to be careful not to dereference these pointers after the objects are destroyed; in this case you're fine, since the lifetimes of the array and vector are contained within those of the objects.
It might make sense to make the Robot class uncopyable, to prevent this kind of mistake.
In C++11, you do this by deleting the copy constructor and copy assignment:
Robot(Robot const &) = delete;
void operator=(Robot const &) = delete;
In older language versions, declare them private, with no implementation; or (better still) derive from a base class that does that.
Here's your problem:
Robot Group[6] = {r1, r2, r3, r4 ,r5, r6};
int leaderID = r1.selectLeader();
The group contains copies of the items. You didn't show us the Robot copy constructor, but I assume it assigns a unique ID to the newly constructed Robot. If so, none of the elements in the group will have an ID equal to your leaderID, and thus your leader pointer is never set.
One solution is to make your Group an array of Robot* pointers rather than an array of Robot objects. A similar problem occurs with your Herd of robots.

Is my compiler confused with what it thinks to be overloaded functions?

I have the following header functions:
float computeDistance3(Vector3f& vec_a, Vector3f& vec_b);
float computeDotProduct3(Vector3f& vecta, Vector3f& vectb);
float computeGeoDotProd3(Vector3f& vecta, Vector3f& vectb);
With the following definitions
float computeDistance3(Vector3f& vec_a, Vector3f& vec_b) {
float x = vec_a.x - vec_b.x;
float y = vec_a.y - vec_b.y;
float z = vec_a.z - vec_b.z;
return sqrt((x * x) + (y * y) + (z * z));
}
float computeDotProduct3(Vector3f& vec_a, Vector3f vec_b) {
return (vec_a.x * vec_b.x)
+ (vec_a.y * vec_b.y)
+ (vec_a.z * vec_b.z);
}
float computeGeoDotProd3(Vector3f& vecta, Vector3f& vectb) {
float amag, bmag, dotProd;
amag = vecta.computeMagnitude();
bmag = vectb.computeMagnitude();
dotProd = computeDotProduct3(vecta, vectb);
bool notZero = (amag != 0.0f && bmag != 0.0f) && dotProd != 0.0f;
if (notZero) {
return cosf(dotProd / (amag * bmag));
} else {
return -1.0f;
}
}
I know that their signatures are the same. Is this confusing the compiler? I'm guessing so, because when I compile the code, I get this:
vector3f.cpp: In function ‘float computeGeoDotProd(Vector3f&, Vector3f&)’:
vector3f.cpp:139:43: error: call of overloaded ‘computeDotProduct3(Vector3f&, Vector3f&)’ is ambiguous
vector3f.cpp:139:43: note: candidates are:
vector3f.h:31:7: note: float computeDotProduct3(Vector3f&, Vector3f&)
vector3f.cpp:127:7: note: float computeDotProduct3(Vector3f&, Vector3f)
Question
What is the solution to unconfusing the compiler?
You're missing an & in the definition:
float computeDotProduct3(Vector3f& vec_a, Vector3f vec_b) {
should be:
float computeDotProduct3(Vector3f& vec_a, Vector3f& vec_b) {
So you end up with two different (overloaded) function prototypes that differ only by the reference & - hence ambiguous.