I saw a few functions in an SDK I'm using do something similar to the following:
void foo( float& fl )
{
if ( std::isnan( fl ) || std::isinf( fl ) )
return ( void )( fl = 0.f );
/*...*/
}
Why?
Why?
On the face of it, someone was just being "clever". You see, there are restrictions placed on a return statement in C++
[stmt.return]
2 The expr-or-braced-init-list of a return statement is called its
operand. A return statement with no operand shall be used only in a
function whose return type is cv void, a constructor, or a
destructor. A return statement with an operand of type void shall be
used only in a function whose return type is cv void. A return
statement with any other operand shall be used only in a function
whose return type is not cv void; [...]
The above makes a simple return ( fl = 0.f ); in that function illegal. Because the expression ( fl = 0.f ) (the return statement's operand) is not of type void. But the author of that function, maybe in an effort to conserve lines of code, or to express some sort of "elegance", decided to force the issue. Since an operand of type void is okay, they added a cast. That's not the only way to make the compiler submit, for instance:
return fl = 0.f , void();
That makes use of the comma operator, and the void() prvalue. It's not code I'd personally advocate one to write. The code in your post and this alternative are unidiomatic, confusing and misguided. Braces ({}) would have made that function much clearer. So while I hope you learned something about C++ from this, don't get in the habit of writing such code. Your colleagues will think more highly of you if you write code they can understand at a glance.
return ( void )( fl = 0.f );
Why?
That is rather unusual code. Casting an expression to void is usually done to suppress a compiler-warning -- it's an idiom that tells the compiler "yes, I know I am throwing this expression's value away -- but I'm doing it deliberately, so you don't need to warn me about it".
What is unusual there is that the author decided to do that in a return statement. It would have been clearer (and logically equivalent) to write
{
fl = 0.0f;
return;
}
instead. The only thing I can think of is that the function used to return a value, and perhaps the author thought he might someday want to change it to return a value again, and would therefore try to keep the code-style looking similar to that of a value-returning function? (If so, it seems a bit "too clever" to me)
It's the same as
void foo( float& fl )
{
if ( std::isnan( fl ) || std::isinf( fl ) )
{
fl = 0.f;
return;
}
/*...*/
}
there is no special reason to prefer one way than another.
Related
I'm writing some code using std::optional's and am wondering if C++17's 'if statements with initializers' will be able to help unpack values?
std::optional<int> optionalInt = GetOptionalInt();
I'm making up the function Unpack here:
if( auto [value, has_value] = optionalInt.Unpack(); has_value )
{
// Use value here.
}
But, my question is. Will C++17 'if statement with initializer' help here? If so, how would it be coded?
Update, this is actually mainly an issue when using optional which is extremely easy to misuse because the optional and *optional both return bools and you don't get any compiler warning when somebody trys to access the value and forgets the *.
There is not, and cannot possibly be, such an Unpack() function.
But you could certainly do:
if (std::optional<int> o = GetOptionalInt(); o) {
// use *o here
}
though the extra o check is kind of redundant.
This is one of those places where it'd be nice if optional<T> modeled a container of at most one element, so that you could do:
for (int value : GetOptionalInt()) {
// possibly not entered
}
but we don't have that interface.
In order for this to work, there has to be a value for the unpacked value if it isn't there.
So
template<class T, class U>
std::pair< T, bool > unpack_value( std::optional<T> const& o, U&& u ) {
return { o.value_or(std::forward<U>(u)), (bool)o } )
}
would do what you wanted.
But as an optional already returns if it is engaged in a bool context you really should just:
if (auto i = get_optional())
then use *i within the body.
...
Now if optional stated that operator* returned a reference, and that return value was defined but accessing it was not defined when it was not engaged, then you could write an Unpack method or function that doesn't require a default value.
As far as I am aware this is not true. And as it doesn't really add anything, I don't see why it should be true.
Maybe this would work:
auto optValue = getOptional();
if (auto value = *optValue; optValue) { ...use value here... }
I often use -1 as the invalid value type when returning from a function, where the input yields incorrect output. For instance, writing an indexing function where the index is out of bounds, instead of throwing an exception, -1 can be returned. But when writing a function that has negative values as possible return types, this technique does not work. What is the correct way to return an invalid type value in such instances?
The technique I use mostly is to set the return type to be of type *int, and return a Pointer to NULL. But, that requires all return values to be of a pointer type, which seems like an extra overhead to the function. Is there an accepted standard for returning values in such cases?
In newer C++, I'd suggest using std::optional<>; if you don't yet have it, boost::optional<>.
One option would be to let your function take a bool& as an output parameter used to indicate if the returned value is valid.
int myFunc(bool& valid); // sets 'valid' to true if result is usable, false otherwise
Users can then do
bool valid = false;
Int result = myFunc(valid);
if (!valid) {
// Handle error
}
// Use result
Not the most pretty solution, but it does the job.
Apart from the answer I provided above, there's a very clean, continuation-passing solution (given you're non-virtual):
template<typename Success, typename Failed>
void parse( const std::string& str, Success s, Failed f )
{
auto a = start_parse(str);
if( a.problem() )
return f(); // you _might_ have an error code here
s( finish_parse(str, a) );
}
Then you might customize by:
Success:
[&i] (int i_) { i = i_; }
out(i), where out(int& output_) returns the above lambda for output_
actual code doing something useful
function to continue with
Failed:
[&i]{ i = 0; }, `[&i]{ i = nullopt; }, or any other default value
[] { throw MyFavouriteException(); }
retry logic
std::terminate()
[]{} if you don't care (or if you're 100% sure it'll succeed)
It might look a little verbose, but IMHO:
it's trivial to read
any other schematics can be mimicked, even if there's no default c'tor
easy to change as well
'you don't pay for what you don't use', can surely be optimized away
every schematic is visible and apparent from code:
for default value, caller sets it, not callee or global
std::optional<> and default value are handled the same
for exception, caller knows better what to throw
for no action, you don't have to lookup the implementation to know this
for std::terminate(), well, you know what to expect
if you 'speak' CPS, you might actually continue and save an if / catch / etc.
The only issue I see is constructor initializer lists. Any thoughts on this?
When refactoring some code, I often encounter this :
bool highLevelFunc foo()
{
// ...
bool result = LesserLevelFunc();
if (!result) return false;
// ... Keep having fun if we didn't return
}
Is there any way to make this a little more sexy and less verbose ? Without any overhead or pitfall of course.
I can think of a macro
#define FORWARD_IF_FALSE(r) if (!r) return r;
bool highLevelFunc foo()
{
// ...
FORWARD_IF_FALSE(LesserLevelFunc());
// ...
}
Anything better, i.e without preprocessor macro?
To me, "readable" code is sexy. I find the original code more readable than your proposal, since the original uses standard C++ syntax and the latter uses a macro which I'd have to go and look up.
If you want to be more explicit, you could say if (result == false) (or better yet, if (false == result) to prevent a possible assignment-as-comparison bug) but understanding the ! operator is a fairly reasonable expectation in my opinion.
That said, there is no reason to assign the return value to a temporary variable; you could just as easily say:
if (!LesserLevelFunc()) return false;
This is quite readable to me.
EDIT: You could also consider using exceptions instead of return values to communicate failure. If LesserLevelFunc() threw an exception, you would not need to write any special code in highLevelFunc() to check for success. The exception would propagate up through the caller to the nearest matching catch block.
Because you might be continuing if LesserLevelFunc returns true, I suggest keeping it pretty close to how it is now:
if (!LesserLevelFunc())
return false;
First of all introducing the macro you are making the code unsafe. Moreover your macro is invalid.
The expression after the negation operator shall be enclosed in parentheses.
#define FORWARD_IF_FALSE(r) if (!( r ) ) return r;
Secondly the macro calls r twice. Sometimes two calls of a function is not equivalent to one call of the same function. For example the function can have some side effects or internal flags that are switched on/off in each call of the function.
So I would keep the code as is without introducing the macro because the macro does not equivalent to the symantic of the original code.
Given the following actions
struct Data {
double d;
void operator()( double dd,
boost::spirit::qi::unused_type,
boost::spirit::qi::unused_type )
{ d = dd; }
};
struct Printer {
void operator()( double dd,
boost::spirit::qi::unused_type,
boost::spirit::qi::unused_type ) const
{ std::cout << dd; }
};
the code
void foo( const std::string &s ) {
Printer p;
boost::spirit::qi::parse( s.begin(), s.end(),
boost::spirit::qi::double_[ p ] );
}
does compile while
double foo( const std::string &s ) {
Data d;
boost::spirit::qi::parse( s.begin(), s.end(),
boost::spirit::qi::double_[ d ] );
return d.d;
}
does not.
Looking at the examples in http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/tutorials/semantic_actions.html, one sees that the function objects use a operator() declared const. The error message C3848 of MSVC suggests something similar.
Is constness required here? The documentation in http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/action.html only says the signature void( Attrib&, Context, bool& ) is required.
Remark: I must admit I don't really understand the sentence
The function or function object is expected to return the value to
generate output from by assigning it to the first parameter, attr.
in this context.
Q.2: Remark: I must admit I don't really understand the sentence
A. You could look at boost spirit semantic action parameters for indepth explanation of it. Here is the short version:
void action_f(std::string& attribute,
qi::unused_type const& context,
bool& flag)
{
boost::fusion::at_c<0>(context.attributes) = "hello world"; // return the attribute value
flag = true; // signal parse success
}
Q.1: Is constness required here? The documentation in http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/spirit/qi/reference/action.html only says the signature void( Attrib&, Context, bool& ) is required.
A. The const-ness may not be explicitely required by the library, however the requirement is implicitely introduced by the C++ language due the way you are using the parser expression1:
The expression template
boost::spirit::qi::double_[ d ]
yields a temporary, which when passed to the qi::parse API can only get bound to a const reference2,3. This is where the 'const' on the whole parser expresion is introduced, and it extends equally to members of the subexpression(s), such as those that store the semantic action, d.
Therefore the instance of d at the time of deferred invocation will be logically const and therefore the operator() will not be selected, whereas operator() const will.
1. Upon more thought, it doesn't really depend on how you use it. The logic of my explanation is sound, but because spirit even supports inline parser expressions, call()-ing parsers is necessarily a const member operation on that parser, and as such all other operations will be in const context anyway. And indeed, in boost::spirit::traits::action_dispatch::operator() you'll see the calleables being passed as F const&, e.g. reflecting this.
2. Spirit V2 does not support move semantics for rules - nor, indeed, does it require them
3. The lifetime of the temporary will be extends to the end of the containing full expression, as per standardese
I've recently been doing a huge refactoring where I was changing a lot of my code to return booleans instead of an explicit return code. To aid this refactoring I decided to lean on the compiler where possible by getting it to tell me the places where my code needed to be changed. I did this by introducing the following class (see here for the lowdown on how this works):
///
/// Typesafe boolean class
///
class TypesafeBool
{
private:
bool m_bValue;
struct Bool_ {
int m_nValue;
};
typedef int Bool_::* bool_;
inline bool_ True() const { return &Bool_::m_nValue; }
inline bool_ False() const { return 0; }
public:
TypesafeBool( const bool bValue ) : m_bValue( bValue ){}
operator bool_() const { return m_bValue ? True() : False(); }
};
Now, instead of using a normal bool type as the return type, I used this class which meant that I couldn't compile something like this any more:
TypesafeBool SomeFunction();
long result = SomeFunction(); // error
Great: it has made the refactoring manageable on a huge codebase by letting the compiler do a lot of the hard work for me. So now I've finished my refactoring and I'd quite like to keep this class hanging around and carry on using it since it affords us an extra level of safety that the built-in bool type doesn't.
There is however one "problem" which is preventing me from doing this. At the moment we make heavy use of the ternary operator in our code, and the problem is that it is not compatible with this new class without explicit casts:
TypesafeBool result = ( 1 == 2 ? SomeFunction() : false ); // error: different types used
TypesafeBool result = ( 1 == 2 ? SomeFunction() : (TypesafeBool)false );
If I could "solve" this issue so that I could use my class in a seamless manner I would probably carry on using it throughout the codebase. Does anyone know of a solution to this issue? Or is it just impossible to do what I want?
In the context of the conditional operator, the type of the expression is the common type of the last two operands. The complete rules to determine this common type are a bit complex, but your case happens to be trivial: if one of the two possible return values is a class type, the other value must have the same class and the common type is obviously also that class.
That means that if one of the operands is a TypesafeBool, then the other must be as well.
Now the problem you're really trying to solve has been solved before. The trick is not providing a class; instead use a typedef. See for instance safe bool.
class CCastableToBool
{
public:
// ...
operator bool() const
{
//...
{
return true;
}
//...
return false;
}
private:
// ...
};
but beware, in C++ it is considered really dangerous to have a class that can be casted to bool. You are warned :-)
you can read this there, SafeBool
You should explicitely call TypesafeBool::True() in all your ternary tests.
TypesafeBool result = ( 1 == 2 ? SomeFunction().True() : false );
I don't know about a seamless manner, the ternary operator has some restrictions on its use...
However, why don't you define two constants ?
TypesafeBool const True = TypesafeBool(true);
TypesafeBool const False = TypesafeBool(false);
And then:
TypesafeBool result = ( 1 == 2 ? SomeFunction() : False );
Of course, it's a bit unorthodox since I play on the capitalization to avoid reusing a reserved word :)
Is it a possibility to make the constructor of TypesafeBool explicit? Of course, now the usage has to be
TypesafeBool result( 1 == 2 ? b : false );
Could you use an assignment operator that takes in a bool as the external argument, as well as one that takes a TypesafeBool? It might be something to try out...
Nice try, but if your code base is large, you are probably better off using a static checker such as PC-Lint to look for implicit bool<->int conversions instead.