I have a function like below:
void add(int&,float&,float&);
and when I call:
add(1,30,30)
it does not compile.
add(1,30.0,30.0) also does not compile.
It seems that in both cases, it gets implicitly converted to double instead of float.
So, do you suggest that it is better to re-define add as add(int&,double&,double&)? Is there any other way of passing making add(1,30,30) work other than casting 30 with float or assigning like "float x = 30 ; add(1,x,x)" ?
I used to think that the compiler will be able to detect that float is a super-set of integer and so would compile it successfully. Apparently, that is not the case.
Thanks!
Your function takes its parameters by reference, not by value, and you can't pass constant integer/floating-point values by non-const reference. You should either change your function to take its parameters by value, or pass actual variables instead of constants, e.g.:
int x = 1;
float y = 30, z = 30;
add(x, y, z);
You can implicitly cast an int to a float or double, but you cannot implicitly cast an int& to a float&.
In your function declaration, you are calling for "pass-by-reference":
void add(int&,float&,float&);
but you are trying to invoke the function using constants. That's the problem.
The upsizing of int to float to double works, but the problem is that you aren't passing variables to add(), so inside add() it can't change them.
Either change add() so it is not passing by reference (drop the &s) or pass variables of the appropriate type.
Related
I have a struct
struct Stuff {
float something (int& prereq) {
float s = prereq+2;
return s;
}
double something_else(int& prereq_ref, float& thing_ref, float& s_ref ){
s2 = s + thing + h;
return s2;
}
};
Then I run a call in my main loop
float thing = 4;
int prereq = 2;
int main() {
Stuff item;
double n = item.something_else(prereq, thing, item.something(prereq));
return 0;
}
The call in main doesn't run, however the following line does
float s = item.something(prereq);
double n = item.something_else(prereq, thing, s);
Am I missing something obvious? I'd rather not waste memory on what seems to be an unnecessary float.
float& is an lvalue reference type. It can only take values that can be assigned to, such as variables.
float s = item.something(prereq);
double n = item.something_else(prereq, thing, s);
Here, s is a variable. It has a place in memory and the expression s = ... would be meaningful. On the other hand,
double n = item.something_else(prereq, thing, item.something(prereq));
Here, the value is item.something(prereq), which is not an lvalue. We can't write item.something(prereq) = ...; it doesn't make sense to assign to the return value of that function.
If you're not planning to modify the function arguments, take them by constant reference or by value.
double something_else(const int& prereq_ref, const float& thing_ref, const float& s_ref)
or
double something_else(int prereq_ref, float thing_ref, float s_ref)
for large data like structures or classes, you might consider using const&, but for integers and floats, it's unnecessary overhead and by-value parameters will do fine.
int foo(int & arg);
This function signature says:
"I will take a reference to the variable you pass in, and I may change it while computing my return value."
If that statement is not true, then your function signature is wrong, or at least misleading to anyone looking at it. It's also worth noting, that if you compute a temporary, it's not in a variable and so it's ineligible to pass into this function. That is the problem you're running into.
Note, this style of function signature is what's known as an "out" parameter (non-const lvalue reference) because it can be thought of as returning an OUTput through a parameter. This design approach is discouraged if other approaches are available, and so it is actually somewhat rare. Any time you find a function with a non-const reference parameter, be sure it's what you mean.
Compare it to this:
int foo(int arg);
This function says:
"I get my own copy and don't care what it came from, variable, reference, temporary, whatever, and I will leave your origianl value alone when computing my return value."
This clearly is what you want to say, so drop the & in your parameter list.
When I try to compile my code I get an error
cannot convert 'float' to 'const float*'.
I was thinking that maybe I needed to be passing in a const but it shouldn't matter.
#include <iostream>
using namespace std;
static float foo(const float *pArray,int n);
int main() {
foo(3.145f,5);
return 0;
}
static float foo(const float *pArray,int n)
{
return 0;
}
you have to pass a pointer
float number=3.145;
foo(&number,n);
C++ is a statically typed and compiled language. That means that the types of any arguments in a function call must, at compile time, be known and match those of the function declaration.
An exact match is not required: conversions are allowed, but there is no conversion from a float to a const float*, i.e. from a floating-point number to a memory address.
In some older code, or some C code, values are passed by pointer. That is, instead of passing the value (of the floating-point number in this case), the memory address of where this number is stored is passed. To use such functions with intermediate results or literals, one must first store the value in some variable and then take the address of that variable to pass as function argument:
void foo(const float*); // function declaration
foo(&(3.1415)); // ERROR: cannot take address of literal
float tmp = 3.1415; // store number in variable
foo(&tmp); // pass address of variable to function
With C++, I struggle to understand one compilation error.
I have this function, with this given signature:
void MethodNMMS::tryNMSA(double factor, double temperature,double& funcWorst,int& iWorst, double& funcTry, double* funcEvals)
{
//...
}
My question concerns argument double& functry (for instance). I call this function tryNMSA() in another function, and I would like functry to be modified during execution of this function. That is why I pass by reference.
Here is the function call:
// other initializations for funcEvals...
double funcTry = 0;
tryNMSA(-1.0,temperature,funcWorst,iWorst,&funcTry,funcEvals);
I put this ampershead because I do want to pass the thing by reference. And that is not permitted. What is wrong, why?
Thanks and regards.
You should not put an ampersand there, as doing so gives a pointer, not a reference to funcTry. Getting a reference to a variable doesn't require any special symbols or operators - just use the name of the variable.
Simply remove the & when you call the function - adding the & means you're trying to pass a pointer.
If you don't put the &, you'll pass a reference. No special syntax necessary.
By passing &funcTry, you are passing the address of funcTry, which would match a function expecting a pointer to double. Your call should simply be
ryNMSA(-1.0,temperature,funcWorst,iWorst,funcTry,funcEvals);
Outside of declarations, a single ampersand means address-of, so &foo means address-of foo.
You should omit the ampersand on the call like this:
tryNMSA(-1.0,temperature,funcWorst,iWorst,funcTry,funcEvals);
The ampersand in the method declaration marks it as a reference argument. When you do ampersand in the method call, you are passing the address of the funcTry variable which is immutable and can't be passed by reference, so compiler gives you an error.
Delete the & in front of the parameter.
Info here:
http://pages.cs.wisc.edu/~hasti/cs368/CppTutorial/NOTES/PARAMS.html
Reference Parameters
When a parameter is passed by reference, conceptually, the actual parameter itself is passed (and just given a new name -- the name of the corresponding formal parameter). Therefore, any changes made to the formal parameter do affect the actual parameter. For example:
void f(int &n) {
n++;
}
int main() {
int x = 2;
f(x);
cout << x;
}
In this example, f's parameter is passed by reference. Therefore, the assignment to n in f is actually changing variable x, so the output of this program is 3.
I won't repeat the other answers. I just wanted to say that this is a recurring issue with learners of C++. The problem is that the & sign has three completely different meanings, and this is not immediately obvious to a beginner:
If x is an l-value, then &x is its address.
If <type> x declares a variable of type <type>, then <type> &x declares a variable of type reference to <type>.
a & b is the bitwise-and operator.
This is similar to the * sign:
If x is a pointer, then *x is its contents.
If <type> x declares a variable of type <type>, then <type> *x declares a variable of type pointer to <type>.
a * b is the multiplication operator.
For some reason, the * operator seems to cause fewer problems than the & operator. Perhaps this is just historical accident: references are newer than pointers.
You can modify a parameter in 2 ways.
Method 1: (reference):
void MethodNMMS::tryNMSA(double& funcTry)
{
funcTry = funcTry + 1.0;
//...
}
// other initializations for funcEvals...
double funcTry = 0;
tryNMSA(funcTry);
Method 2: (pointer):
void MethodNMMS::tryNMSA(double* funcTry)
{
(*funcTry) = (*funcTry) + 1.0;
//...
}
// other initializations for funcEvals...
double funcTry = 0;
tryNMSA(&funcTry);
Make up your mind and use only one of them, it saves a great deal of confusion.
(actually, here you can use one more method - the return value). It's useful to put emphasis on this one value being main purpose of the function.
double MethodNMMS::tryNMSA(double funcTry)
{
//...
return funcTry + 1.0;
}
// other initializations for funcEvals...
double funcTry = 0;
funcTry = tryNMSA(funcTry);
So I have a class made in c++ and need to convert it into vb.net but I got problem converting a certain part of a function.
void deg_min_sec2decimal(double deg, double min, double sec, double& dec_deg)
{
dec_deg = (deg+min/60.0+sec/3600.0);
}
What type of variable is "double&", I know a double but what's with the "&"?
It isn't " double &dec_deg" so it isn't an adres (pointers ect.)?
and how would i convert that to vb.net?
Grtz
It's a reference. That means that whatever you set the value to inside the function, the original variable that was passed in from outside will have that value.
You can convert this to VB by using ByRef or making the function return the result of that expression instead of taking the double&, and setting the variable you would have passed in to the result of the function.
So if you had this before:
double retval;
deg_min_sec2decimal(something, something2, something3, retval);
You'd change that to
Dim retval = deg_min_sec2decimal(something, something2, something3)
(I don't know VB so that syntax might be wrong, but you get the idea.)
I'd go with the latter because returning things through arguments is usually only used when you need more than one return value, and that function isn't even returning anything.
double& is just a double passed by reference. In VB.NET, it would be declared ByRef dec_deg as Double.
EDIT: However, I would recommend instead of using a void function to set a value by reference, just change the return type to double and return the expression instead of having to pass a variable by reference.
double& is a reference to a double. This means in that case that the function can change the value of the passed parameter.
In VB, you do this by ByRef parameters:
Sub deg_min_sec2decimal(deg as Double, min as Double, sec as Double, ByRef dec_deg as Double)
Yes, it is an address ("reference" is the correct C++ term). It doesn't matter if the '&' is on the left or the right, C++ doesn't care about whitespace.
double& d; // Same as...
double &d;
Yes, it's an address, but the terminology is a reference. Meaning, what you do to the parameter will effect the variable passed to it. In VB, the equivilant is the ByRef word:
sub someFunc(ByRef someVar as double)
I am studying a C++ tutorial. I can't understand this example on Pointers to Functions.
Here it is:-
// pointer to functions
#include <iostream>
using namespace std;
int addition (int a, int b)
{ return (a+b); }
int subtraction (int a, int b)
{ return (a-b); }
int operation (int x, int y, int (*functocall)(int,int))
{
int g;
g = (*functocall)(x,y);
return (g);
}
int main ()
{
int m,n;
int (*minus)(int,int) = subtraction;
m = operation (7, 5, addition);
n = operation (20, m, minus);
cout <<n;
return 0;
}
The lines "m = operation (7, 5, addition);" and "n = operation (20, m, minus);" are treated the same way, but while minus has been declared as a pointer to function, addition hasn't. So, how did they both work the same way?
Using a function name as an argument parameter in a function call, or on the right-hand side of the assignment operator in C/C++, causes a conversion to a function pointer to the original function.
So for instance if you have a function like
void my_function(int a, int b);
If you use the identifier my_function on the right-hand side of the assignment operator like this:
void (*my_function_ptr)(int, int) = my_function;
Then my_function implicitly converts from a function object to a function pointer of type void (*)(int, int), initializing the identifier my_function_ptr so that it points to my_function. The same situation would also occur when passing my_function to another function like:
void another_function(int, void (*)(int, int));
another_function(5, my_function);
In the call to another_function(), the identifier my_function is again converted to a pointer to the original function.
Finally, keep in mind this only occurs if you simply pass the identifier name to a function argument, or put it on the right-hand side of the assignment operator. Adding a function call using the () symbols and an optional argument list (i.e., my_function(5, 6)) will evaluate the function, not cause a conversion to a function pointer.
The type of addition is int (&)(int,int) which can decay into a pointer of type int (*)(int,int) which is same as that of operation function's third parameter. So you can pass addition as third argument to the function operation.
The type of subtraction is also the same as that of addition. In your code, the address of subtraction is first stored as local variable of the compatible type, and then that variable is passed as argument to operation function.
In case of addition, it's address is not stored as local variable, instead its passed as such to operation. Its initializing the function's third parameter directly with the function's address, without using any local variable.
A conversion from int (&)(int,int) to int (*)(int,int) occurs in both cases. Its just that with substration, the conversion occurs when initializing the local variable, and with addition, the conversion occurs when initializing the function parameter.
An analogy would be this:
void f(double a, double b) {}
int main()
{
double x = 100;//first store 100 in a local variable
f(x, 100); //pass the local variable as first arg,
//and pass 100 as second arg without using any local variable.
}
Note the type of 100 is int, so it first converts to double type, which is then stored as local variable x, which in turn is passed to the function f as first argument. And the second argument 100 is passed directly to the function, so even now it first converts to double and then it initializes b (the second parameter of the function).
Again, a conversion from int to double occurs in both cases. Its just that first argument conversion occurs when initializing the local variable x, and second argument conversion occurs when initializing the second parameter of the function.
name of the function in C is resolved to its address. So this works:
int (*minus)(int,int) = subtraction;
Both solutions work: the third argument of "operation" must be a function pointer.
Please note that the ampersand is optional:
m = operation (7, 5, &addition);
also works.
By passing "addition" to operation() you're effectively assigning it to "functocall". It's exactly the same as assigning "subtraction" to "minus". They work the same way because they are the same.
The real question is, why don't you need an ampersand (&) to take the function's address?
p.s. Apart from the gratuitous use of iostream, namespace and cout, this is actually a C tutorial. Right?
C++ provides implicit function-to-pointer conversion (see 4.3 in C++ 2003 standard). In your example, it is used both for assignment of subtraction to minus and for conversion of addition to the parameter type accepted by operation. So essentially both calls are done the same way, just in one case you explicitly created an intermediate variable of type pointer-to-function. And in both cases an optimizing compiler will simply pass the address of a corresponding function into operation.