Recently, I had a bug where, we changed the function from
void update_waypoint_heading(const double new_observation, waypoint)
{
// ....
waypoint.heading = default_heading_deg * waypoint.some_magic_number
}
// Call the function and the function will calculate new heading and mutate heading in waypoint
update_waypoint_heading(new_observation, waypoint);
to
double update_waypoint_heading(const double new_observation, waypoint)
{
// ....
return default_heading_deg * waypoint.some_magic_number
}
// Here the caller is supposed to be responsible for mutation
waypoint.heading = update_waypoint_heading(new_observation, waypoint);
We had a bug where we changed the function but did not change the caller. So we ended with
update_waypoint_heading(new_observation, waypoint);
Where update_waypoint_heading started to return the new heading. But it never got set to the waypoint. This was also perfectly legal for the compiler.
Is it possible to declare a parameter as mutant (like the opposite of const), where it will throw a compiler error if it does not get mutated. So that I can catch these cases at compile time
No, and it wouldn't make much sense either.
You pass an argument into a function, and want a keyword to mandate that the calling scope then assigns the result of that function into some part of the same thing you passed as an argument?
This is very convoluted.
If a function returns a result that ought to be used, then that is documented by its return type. If it modifies its by-reference arguments, then that should also be documented. Do not switch from one to the other after you've already got code using that function!
HOWEVER! There is the nodiscard attribute which will prevent the result of calling the function from simply being, well, discarded. That would have flagged this case up, and may be what you're really looking for.
You'll need a nice C++17 compiler to use it.
I still think this is a bit leaky, though. It's not up to your function to decide what the calling scope does with its result. Just don't change function semantics! Write a new function with a new name if you need to. "Update" is no longer a good descriptive name for what it does anyway.
Related
I have couple questions regarding some C++ rules.
Why am I able to call a function/method from outside the class in the namespace when I include the return type? (look at the namespace test2::testclass2 in the code below) i.e. this works:
bool b = testclass1::foo<int>(2);
whereas this doesn't: - (it doesn't even compile - compiler throws that this is function redeclaration)
testclass1::foo<int>(2);
C++ complains that it is a function redeclaration. Is that so?
This line:
bool b = testclass1::foo<int>(2);
gets called first before anything else. Is this because static methods get created always first before anything else in C++?
Where can I find those rules? I have a few C++ books at home, so if someone would be kind enough to either point out a book (and chapter or page) or direct me to a website I would greatly appreciate it.
Here below is the sample (partial) code that I tested at home with Visual Studio 2008:
class testclass1
{
public:
testclass1(void);
~testclass1(void);
template<class A> static bool foo(int i)
{
std::cout <<"in static foo";
return true;
}
};
namespace test2
{
class testclass2
{
public:
testclass2(void);
~testclass2(void);
};
bool b = testclass1::foo<int>(2);
}
EDIT:
A few people mentioned that I need to call this inside the function and this will work without any problem.
I understand that; the only reason I asked this question is because I saw this code somewhere (in someone's elses project) and was wondering how and why this works. Since I never really seen anyone doing it before.
Also, this is used (in multiple places) as a way to call and instantiate a large number of classes like this via those function calls (that are outside). They get called first before anything else is instantiated.
C++ is not Python. You write statements in functions and execution starts from the main method. The reason bool b = ... happens to work is that it's defining the global variable b and the function call is merely the initialization expression.
Definitions can exist outside functions while other statements can only exist inside a function body.
Why am I able to call a function/method from outside the class in the namespace when I include the return type? (look at the namespace test2::testclass2)
Your declaration of b is not inside a function, so you are declaring a global variable. If you were inside a function's scope, your second statement would work, but outside a function it makes no sense.
This also answers your second question.
Of course, you wouldn't be allowed to call it this way (i.e. not as a method of an object) if it weren't a static member function.
You can find the rules on e.g. Koenig lookup and template in the standard documentation -- good luck with navigating that! You're not mentioning which compiler you are testing, but I'm not entirely sure it's compliant!
As Mehrdad points out, you're declaring and initializing a global variable within the test2 namespace: this has nothing to do with static methods.
if you write this inside a function like below then it works without a problem. As mentioned above, you need to call these functions from within a function unless you are using the function to initialize a global variable ...
int main()
{
testclass1::foo<int>(2);
return 0;
}
1. First, a helpful correction: you said "...when I include the return type". I think you might be misunderstanding what the <int> part of testclass1::foo<int>(2) does. It doesn't (necessarily) specify the return type, it just provides a value for the template argument "A".
You could have chosen to use A as the return type, but you have the return type hard-coded to "bool".
Basically, for the function as you have written it you will always need to have the <> on it in order to call it. C++ does allow you to omit the <args> off the function when the type can be deduced from the function arguments; in order to get it to do that you have to use the type argument A in your function arguments. For instance if you declared the function this way instead then you could call it without the <>:
template<class A> static bool foo(A i);
In which case it you could call "foo(2)" and it would deduce A to be "int" from the number two.
On the other hand there isn't any way to make it deduce anything based on what you assign the function to. For template argument deduction it only looks at the arguments to the function, not what is done with the result of calling the function. So in:
bool b = testclass1::foo(2);
There is no way to get it to deduce "bool" from that, not even if you made A the return type.
So why doesn't the compiler just tell you "you needed to use <> on the function"? Even though you declared foo once as a template function, you could have also overloaded it with a non-template version too. So the compiler doesn't just automatically assume that you're trying to call a template function when you leave the <> off the call. Unfortunately having NOT assumed you were calling template-foo and not seeing any other declaration for foo, the compiler then falls back on an old C style rule where for a function that takes an int and returns an int, in a very old dialect of C you didn't need to declare that kind of before using it. So the compiler assumed THAT was what you wanted - but then it notices that template-foo and old-crufty-C-foo both take an int parameter, and realizes it wouldn't be able to tell the difference between them. So then it says you can't declare foo. This is why C++ compilers are notorious for giving bad error messages - by the time the error is reported the compiler may have gone completely off the rails and be talking about something that is three or four levels removed from your actual code!
2. Yes you're exactly right.
3. I find that the C++ references and whitepapers that IBM makes available online are the most informative. Here's a link to the section about templates: C++ Templates
This question already has answers here:
best practice for parameters?
(5 answers)
Closed 9 years ago.
I have a member function in my class like this:
int MyClass::m_Func(int& val);
in which, I do some operation and put the result in val. And depending upon the result of the operation, I returned different values from the function. Like, if it is successful, I return 0 or other values if any error occurs.
One of my friend told me that it is not a good practice to pass a reference of a variable to a member function. Is it true? If yes, why so?
The main reason why this practice is somewhat suspicious, and why I'd generally recommend against it, is that users, when they call your function,
int val;
obj.my_Func(val);
may not be aware of the fact that the value of val is in fact modified. This may be more or less obvious when the function has only one parameter and no return value other than an error code, but as soon as you have a slightly more complex function call, e.g.
int x,y,rad,len;
obj.calculate_coord(x,y,rad,len);
the intention may be to calculate rad and len from x and y, or vice versa, or something entirely different. Since the argument names are chosen by the user, and their order or types do not give any hint on which ones serve as input and which ones as output parameters, this can cause misunderstandings, hence make the code harder to maintain and give rise to bugs.
On the other hand, it is quite straight-forward to use C++ syntax to properly return not just the value or the error code, but a combination of one or more values and an error code.
In the simplest case you may use a function like this (using C++11 syntax):
std::tuple<int,int,int> my_Func(int input)
{
/* calculate.. */
return { error_code , val1 , val2 };
}
to return two values and an error code. There is no question that input is a pure input parameter (passed by value) and the return value is complex and includes everything you might want to return.
Contrary to what some programmers may suggest, this does not usually cause a lot of unnecessary copying, even when the return value is much larger (because of return value optimization, and in C++11 because of move semantics).
There may be exceptions, especially in pre-C++11, i.e. special cases where move semantics can't be used or for some reason return value optimization doesn't apply. There may also be cases where code profiling reveals that a) the function is used extremely heavily, and b) for whatever reason, passing the output through a reference is faster. In these cases, passing an output parameter by reference may be the right technique to use.
Of course, what I said above applies only to the use of references as output parameters, i.e. as an indirect way of returning values to the user, in particular when the fact that the function modifies some of its parameters isn't made obvious by its name.
There can be many other, and valid, reasons for passing by reference, esp. by const-reference.
I guess, that your friend did not actually complain about passing a reference to a variable to a method rather than about the error reporting technique you've chosen (actually, people usually are encouraged to pass parameters by reference, it's a lot safer than passing by pointer). In C++, one usually uses exceptions to check for errors; your code is a little C-style. So instead of:
int res;
myInstance->m_Func(res);
if (res != 0)
// do sth
I'd rather write:
MyClass::m_Func()
{
if (some_condition)
throw std::exception("Error!");
}
// (...)
try
{
myInstance->m_Func();
}
catch (...)
{
// do sth
}
Disclaimer: Opinions will differ wastly on this one, since it is a matter of style, convention, etc.
What you have there is a so-called "out-parameter", i.e. your function does not pass its result through the returned value, but through the parameter. This is mainly because the returned value is occupied by the error code (i.e. the success indicator).
In many languages like C, this is a common usage of functions and error handling. In some applications of C++ where using exceptions is not possible for some reason, this style may be adopted as well. In "pure" C++ however, you have exceptions for the error handling. It is common that any parameter to a function is an input parameter, and any value prodced by the function is passed out via the returned value. If there is more than one value to return, the values are bundled in a std::pair, std::tuple or some struct.
Using exceptions might be too harsh in your case, maybe because non-success is not really an exceptional case but a common and expected outcome of the function. In that case, return a pair of values - one success indicator and one result value. Bundling them together might look odd at first but is a viable solution, since you have to evaluate them both anyways. But remember, in most cases it will be cleaner to throw an exception if the function cannot execute its task, i.e. calculate a useful return value.
I'm receiving the following warning:
warning: converting from 'void (MyClass::*)(byte)' to 'void (*)(byte)'
This is because I need to pass as argument a member function instead of an ordinary function. But the program is running correctly.
I'd like to disable this warning (Wno-bad-function-cast doesn't work for C++) or to implement a different way to pass a member function.
No. Take this warning seriously. You should rather change your code to handle this scenario.
Pointer to member function(void (MyClass::*)(byte)) and normal function pointer (void (*)(byte)) are entirely different. See this link. You cannot cast them just like that. It results in undefined behavior or crash.
See here, how they are different:
void foo (byte); // normal function
struct MyClass {
void foo (byte); // member function
}
Now you may feel that, foo(byte) and MyClass::foo(byte) have same signature, then why their function pointers are NOT same. It's because, MyClass::foo(byte) is internally resolved somewhat as,
void foo(MyClass* const this, byte);
Now you can smell the difference between them.
Declare pointer to member function as,
void (MyClass::*ptr)(byte) = &MyClass::foo;
You have to use this ptr with the object of MyClass, such as:
MyClass obj;
obj.*ptr('a');
You can't pass a function that takes two arguments to a place that expects a function that takes one. Can't be done, forget about it, period, end of story. The caller passes one argument to your function. It doesn't know about the second argument, it doesn't pass it to your function, you can't make it do what you want however hard you try.
For the very same reason you can't pass a non-static member function where a regular function is expected. A member function needs an object to operate on. Whatever code calls your function doesn't know about the object, there's no way to pass it the object, and there's no way to make it use the right calling sequence that takes the object into account.
Interfaces that take user's functions, without taking additional data that the user might want to pass to his function, are inherently evil. Look at the qsort() function from the C standard library. That's an example of an evil interface. Suppose you want to sort an array of string according to some collation scheme defined externally. But all it accepts is a comparison function that takes two values. How do you pass that collation scheme to your comparison function? You can't, and so if you want it working, you must use an evil global variable, with all the strings attached to it.
That's why C++ has moved away from passing function pointers around, and towards function objects. Function objects can encapsulate whatever data you want.
Also, this may be helpful
union FuncPtr
{
void (* func)(MyClass* ptr, byte);
void (MyClass::* mem_func)(byte);
};
Well, here we are. Yet another proposed practice that my C++ book has an opinion on. It says "a returning-value(non-void) function should not take reference types as a parameter." So basically if you were to implement a function like this:
int read_file(int& into){
...
}
and used the integer return value as some sort of error indicator (ignoring the fact that we have exceptions) then that function would be poorly written and it should actually be like
void read_file(int& into, int& error){
}
Now to me, the first one is much clearer and nice to use. If you want to ignore the error value, you do so with ease. But this book suggests the later. Note that this book does not say returning value functions are bad. It rather says that you should either only return a value or you should only use references.
What are your thoughts on this? Is my book full of crap? (again)
The advice is silly. A direct return value is much smaller and easier to type.
Direct return:
if (read_file(...)) {
... handle problem ...
}
Indirect return:
int status;
read_file(..., status);
if (status) {
... handle problem ...
}
Edit: a bigger issue is whether to use non-const reference parameters at all. It can be surprising to have side effects come flying out of the parameters. One coding standard says that reference parameters should be const and output parameters should use pointers. That way the reader gets a & at the point of call that shouts out "something happens to this parameter".
I think it's more important to be consistent across a project than to evangelize one way as better than another.
It's a rather uninteresting and subjective style debate. Personally I'd rather return a std::pair, a struct, or (in TR1) a tuple.
They are attempting to teach you the practice of "if you return a value, do not modify the variables in the call parameters"
Instead, you can do something like the following:
int read_file(const int& into){ ... }
My syntax might be slightly off, but the const tells it you cannot change it inside the method, but you still get the pass by reference, which is nice with objects. With the int, it doesn't really buy you anything.
Edit: Additionally, as others have noted, if your goal is to have multiple return values, then it is usually a better idea to either do as the book suggests, or to instead create a "composite" return type - use a pair, your own custom type, etc.
//somewhere deep in the code space
a = func(i); //i is modified inside func() or not?
j = i; //what is this for? depends on the answer to the first question
If the code was written with respect to the rule that the book suggests, you can be sure that "i" is not modified just by looking at the call site, thus the code says more to you than otherwise
Anyway, I would prefer to return a tuple, not modifying by reference
I'm trying to fix something in some Objective C++ (?!) code. I don't know either of those languages, or any of the relevant APIs or the codebase, so I'm getting stymied left and right.
Say I have:
Vector<char, sizeof 'a'>& sourceData();
sourceData->append('f');
When i try to compile that, I get:
error: request for member 'append' in 'WebCore::sourceData', which is of non-class type 'WTF::Vector<char, 1ul >& ()();
In this case, Vector is WTF::Vector (from WebKit or KDE or something), not STD::Vector. append() very much is supposed to be a member of class generated from this template, as seen in this documentation. It's a Vector. It takes the type the template is templated on.
Now, because I never write programs in Real Man's programming languages, I'm hella confused about the notations for references and pointers and dereferences and where we need them.
I ultimately want a Vector reference, because I want to pass it to another function with the signature:
void foobar(const Vector<char>& in, Vector<char>& out)
I'm guessing the const in the foobar() sig is something I can ignore, meaning 'dont worry, this won't be mangled if you pass it in here'.
I've also tried using .append rather than -> because isn't one of the things of C++ references that you can treat them more like they aren't pointers? Either way, its the same error.
I can't quite follow the error message: it makes it sound like sourceData is of type WTF:Vector<char, 1ul>&, which is what I want. It also looks from the those docs of WTF::Vector that when you make a Vector of something, you get an .append(). But I'm not familiar with templates, either, so I can't really tell i I'm reading that right.
EDIT:
(This is a long followup to Pavel Minaev)
WOW THANKS PROBLEM SOLVED!
I was actually just writing an edit to this post that I semi-figured out your first point after coming across a reference on the web that that line tells the compiler your forward declaring a func called sourceData() that takes no params and returns a Vector of chars. so a "non-class type" in this case means a type that is not an instance of a class. I interpreted that as meaning that the type was not a 'klass', i.e. the type of thing you would expect you could call like .addMethod(functionPointer).
Thanks though! Doing what you suggest makes this work I think. Somehow, I'd gotten it into my head (idk from where) that because the func sig was vector&, I needed to declare those as &'s. Like a stack vs. heap pass issue.
Anyway, that was my REAL problem, because I tried what you'd suggested about but that doesn't initialize the reference. You need to explicitly call the constructor, but then when I put anything in the constructor's args to disambiguate from being a forward decl, it failed with some other error about 'temporary's.
So in a sense, I still don't understand what is going on here fully, but I thank you heartily for fixing my problem. if anyone wants to supply some additional elucidation for the benefit of me and future google people, that would be great.
This:
Vector<char, sizeof 'a'>& sourceData();
has declared a global function which takes no arguments and returns a reference to Vector. The name sourceData is therefore of function type. When you try to access a member of that, it rightfully complains that it's not a class/struct/union, and operator-> is simply inapplicable.
To create an object instead, you should omit the parentheses (they are only required when you have any arguments to pass to the constructor, and must be omitted if there are none):
Vector<char, sizeof 'a'> sourceData;
Then you can call append:
sourceData.append('f');
Note that dot is used rather than -> because you have an object, not a pointer to object.
You do not need to do anything special to pass sourceData to a function that wants a Vector&. Just pass the variable - it will be passed by reference automatically:
foobar(sourceData, targetData);
Dipping your toes in C++ is never much fun. In this case, you've run into a couple of classic mistakes. First, you want to create an instance of Vector on the stack. In this case the empty () is interpreted instead as a declaratiton of a function called sourceData that takes no agruments and returns a reference to a Vector. The compiler is complaining that the resulting function is not a class (it's not). To create an instance of Vector instead, declare the instance without the () and remove the &. The parentheses are only required if you are passing arguments to the instance constructor and must be omitted if there are no arguments.
You want
Vector<char, sizeof 'a'> sourceData;
sourceData.append('f');
Vector<char, sizeof 'a'> outData; //if outData is not instantiated already
foobar(sourceData, outData);
This Wikipedia article gives a decent introduction to C++ references.