I have the following code:
Foo a;
if (some_fairly_long_condition) {
a = complicated_expression_to_make_foo_1();
} else {
a = complicated_expression_to_make_foo_2();
}
I have two issues with this:
a is a const and should be declared so
the "empty" constructor, Foo() is called for no reason (maybe this is optimised away?)
One way to fix it is by using the ternary operator:
const Foo a = some_fairly_long_condition?
complicated_expression_to_make_foo_1():
complicated_expression_to_make_foo_2();
Is this good practice? How do you go about it?
To answer the second part of your question:
I usually put the initialization code into a lambda:
const Foo a = [&]()->Foo{
if (some_fairly_long_condition) {
return complicated_expression_to_make_foo_1();
} else {
return complicated_expression_to_make_foo_2();
}
}();
In most cases you should even be able to omit the trailing return type, so you can write
const Foo a = [&](){ ...
As far as the first part is concerned:
I'd say that greatly depends on how complex your initialization code is. If all three parts are really complicated expressions (and not just a function call each) then the solution with the ternary operator becomes an unreadable mess, while the lambda method (or a separate named function for that matter) allows you to break up those parts into the respective sub expressions.
If the problem is to avoid ternaty operator and your goal is to define the constant a, this code is an option:
Foo aux;
if (some_fairly_long_condition) {
aux = complicated_expression_to_make_foo_1();
} else {
aux = complicated_expression_to_make_foo_2();
}
const Foo a(aux);
It is a good solution, without any new feature ---as lambdas--- and including the code inline, as you want.
Related
In my work's codebase, I see the following
class custom {
auto set_data_type(custom_type_t type_t) -> custom & {
// set some stuff
// return *this;
}
}
Why can't we simply just do
class custom {
custom & set_data_type(custom_type_t type_t) {
// set some stuff
// return *this;
}
}
What is the point of using auto in this case when you already know the return type and already wrote it out in the ->... place?
It seems auto would only be beneficial if it is used with decltype(arg) and where arg may have varying return types?
I would say style.
Moreover, it allows to be consistent in any contexts,
simple one (as this one),
more useful ones ("complex" decltype(arg) , scoping (-> iterator instead of typename C::iterator)
or required one (lambda).
To me the most use of this feature is when you're using nested type when defining a function body in a cpp file:
class MyLongClassName
{
using ANestedType = ...;
ANestedType myFunction();
}
When you implement to function body, this syntax avoid some repetition:
MyLongClassName::ANestedType MyLongClassName::myFunction()
{ ... }
versus
auto MyLongClassName::myFunction() -> ANestedType
{ ... }
I believe, "auto" should not be used at all. IMHO, this is ugly sibling of void*; it hides types from programmer, while it is better to know exactly what type is used; this makes one's programming style clumsy, confuses and invites bugs. While the only "reasonable" use of this is typename "shortening", it is actually ridiculous, because short type names don't need to replaced, and for long names there is another keyword. IMHO.
Think about this code in C/C++:
bool cond = true;
while(cond){
std::cout << "cond is currently true!";
}
Is it possible to create a function that can be called like this?
myFunction(some_parameters_here){
//Code to execute, maybe use it for callbacks
myOtherFunction();
anotherFunction();
}
I know you can use function pointers and lambda functions, but I was wondering if you can. I'm pretty sure there is a way to do so, because how would while() exist?
while(condition) { expression } is not a function but a control structure / a separate language construct; it executes expression again and again as long as condition evaluates to true (i.e. something != 0).
an function definition of the form void myFunction(int someParameter) { expression }, in contrast, is executed only when it is called by another function.
Hope it helps a bit;
Caution: this solution comes without the guarantee that your code reviewer will like it.
We can use a trick similar to the one Alexandrescu uses for his SCOPE_EXIT macro (awesome one-hour conference, this bit is at 18:00).
The gist of it: a clever macro and a dismembered lambda.
namespace myFunction_detail {
struct Header {
// Data from the construct's header
};
template <class F>
void operator * (Header &&header, F &&body) {
// Do something with the header and the body
}
}
#define myPrefix_myFunction(a, b, c) \
myFunction_detail::Header{a, b, c} * [&]
Using it as follows:
myPrefix_myFunction(foo, bar, baz) {
}; // Yes, we need the semicolon because the whole thing is a single statement :/
... reconstitutes a complete lambda after macro expansion, and lands into myFunction_detail::operator* with acess to foo, bar, baz, and the body of the construct.
What does the following code do in C/C++?
if (blah(), 5) {
//do something
}
Comma operator is applied and the value 5 is used to determine the conditional's true/false.
It will execute blah() and get something back (presumably), then the comma operator is employed and 5 will be the only thing that is used to determine the true/false value for the expression.
Note that the , operator could be overloaded for the return type of the blah() function (which wasn't specified), making the result non-obvious.
If the comma operator is not overloaded, the code is similar to this:
blah();
if (5) {
// do something
}
If the comma operator is overloaded, the result will be based on that function.
#include <iostream>
#include <string>
using namespace std;
string blah()
{
return "blah";
}
bool operator,(const string& key, const int& val) {
return false;
}
int main (int argc, char * const argv[]) {
if (blah(), 5) {
cout << "if block";
} else {
cout << "else block";
}
return 0;
}
(edited to show comma operator overloading scenario. thanks to David Pierre for commenting on this)
I know one thing that this kind of code should do: it should get the coder fired. I would be quite a bit afraid to work next to someone who writes like this.
In the pathological case, it depends on what the comma operator does...
class PlaceHolder
{
};
PlaceHolder Blah() { return PlaceHolder(); }
bool operator,(PlaceHolder, int) { return false; }
if (Blah(), 5)
{
cout << "This will never run.";
}
I would say that depends on blah().
On a more broad answer. The comma operator (non overloaded) resolves as in, execute the first part and return the second part.
So if you have (foo(),bar()) Both functions will be executed, but the value of the expression evaluates to bar() (and the type of the expression as well).
While I won't say there are fair usages for that, is usually considered a bit hard to read code. Mainly because not many languages shares such constructs. So As a personal rule of thumb I avoid it unless I am adding code to a preexistent expression and don't want to change completely its format.
Example: I have a Macro (not discussing if you should use macros or not, sometimes its not even you that wrote it)
FIND_SOMETHING(X) (x>2) ? find_fruits(x) : find_houses(x)
And I usually use it in assignments like my_possession = FIND_SOMETHING(34);
Now I want to add log to it for debuggin purposes but I cannot change the find functions,. I could do :
FIND_SOMETHING(X) (x>2)? (LOG("looking for fruits"),find_fruits(x)):(LOG("looking for houses"),find_houses(x))
I use sometimes constructs like this for debugging purposes. When I force the if close to be true regardless of the return value of blah.
It's obvious that it should never appear in production code.
The following was written assuming it is C code, either in a C file or within a C block of a C++ file:
It is a pointless if. It will call blah(), however the result of blah() is not considered by if at all. The only thing being considered is 5, thus the if will always evaluate to true. IOW you could write this code as
blah();
// do something
without any if at all.
I think many of you have this kind of code somewhere:
int foo;
switch (bar) {
case SOMETHING: foo = 5; break;
case STHNELSE: foo = 10; break;
...
}
But this code has some drawbacks:
You can easily forget a "break"
The foo variable is not const while it should be
It's just not beautiful
So I started wondering if there was a way to "improve" this kind of code, and I got this little idea:
const int foo = [&]() -> int {
switch (bar) {
case SOMETHING: return 5;
case STHNELSE: return 10;
...
}
}();
Note: the first pair of parentheses it not mandatory, but MSVC++ doesn't support this yet
You can use the same trick with if-else where the ternary operator would be too complicated, variables that require to be passed by pointers to be initialized (like for DirectX functions), etc.
My questions are:
Is there anything wrong with this code that I didn't see?
Do you find it better than the one above?
g++ seems to inline the function, but do you think that all compilers will do so?
EDIT: this is what I mean by "DirectX functions"
_xAudio2 = [&]() -> std::shared_ptr<IXAudio2> {
IXAudio2* ptr = nullptr;
if (FAILED(XAudio2Create(&ptr, xAudioFlags, XAUDIO2_DEFAULT_PROCESSOR)))
throw std::runtime_error("XAudio2Create failed");
return std::shared_ptr<IXAudio2>(ptr, [](IUnknown* ptr) { ptr->Release(); });
}();
This is a fairly common technique in other languages. Almost every high-level feature of Scheme is defined in terms of lambdas that are immediately called.
In JavaScript it is the basis of the "module pattern", e.g.
var myModule = (function() {
// declare variables and functions (which will be "private")
return {
// populate this object literal with "public" functions
};
})();
So an anonymous function is declared and immediately called, so that any internal details are hidden and only the return value is exposed externally.
The only downsides is that on a casual reading of the code, the return statements will appear to be returning from the outer function (there was intense controversy about this during the Java lambda wars). But this is just something you have to get used to once your language has lambdas.
There are many language features in an imperative language like C++ which would benefit from being able to return a value (rather than being like a void function). For example, if has an alternative, the tertiary operator expr ? a : b.
In Ruby pretty much all statements can be evaluated, so there is no need for a separate syntax where a return value can be supplied. If C++ worked that way, this would mean things like:
auto result = try
{
getIntegerSomehow();
}
catch (const SomeException &)
{
0;
}
I don't see any reason at all to use a switch case in such a case. Any decent compiler will generate just as fast code with if statements as with a switch case.
if(bar == SOMETHING)
foo = 5;
else if(bar == STHNELSE)
foo = 10;
What does the following code do in C/C++?
if (blah(), 5) {
//do something
}
Comma operator is applied and the value 5 is used to determine the conditional's true/false.
It will execute blah() and get something back (presumably), then the comma operator is employed and 5 will be the only thing that is used to determine the true/false value for the expression.
Note that the , operator could be overloaded for the return type of the blah() function (which wasn't specified), making the result non-obvious.
If the comma operator is not overloaded, the code is similar to this:
blah();
if (5) {
// do something
}
If the comma operator is overloaded, the result will be based on that function.
#include <iostream>
#include <string>
using namespace std;
string blah()
{
return "blah";
}
bool operator,(const string& key, const int& val) {
return false;
}
int main (int argc, char * const argv[]) {
if (blah(), 5) {
cout << "if block";
} else {
cout << "else block";
}
return 0;
}
(edited to show comma operator overloading scenario. thanks to David Pierre for commenting on this)
I know one thing that this kind of code should do: it should get the coder fired. I would be quite a bit afraid to work next to someone who writes like this.
In the pathological case, it depends on what the comma operator does...
class PlaceHolder
{
};
PlaceHolder Blah() { return PlaceHolder(); }
bool operator,(PlaceHolder, int) { return false; }
if (Blah(), 5)
{
cout << "This will never run.";
}
I would say that depends on blah().
On a more broad answer. The comma operator (non overloaded) resolves as in, execute the first part and return the second part.
So if you have (foo(),bar()) Both functions will be executed, but the value of the expression evaluates to bar() (and the type of the expression as well).
While I won't say there are fair usages for that, is usually considered a bit hard to read code. Mainly because not many languages shares such constructs. So As a personal rule of thumb I avoid it unless I am adding code to a preexistent expression and don't want to change completely its format.
Example: I have a Macro (not discussing if you should use macros or not, sometimes its not even you that wrote it)
FIND_SOMETHING(X) (x>2) ? find_fruits(x) : find_houses(x)
And I usually use it in assignments like my_possession = FIND_SOMETHING(34);
Now I want to add log to it for debuggin purposes but I cannot change the find functions,. I could do :
FIND_SOMETHING(X) (x>2)? (LOG("looking for fruits"),find_fruits(x)):(LOG("looking for houses"),find_houses(x))
I use sometimes constructs like this for debugging purposes. When I force the if close to be true regardless of the return value of blah.
It's obvious that it should never appear in production code.
The following was written assuming it is C code, either in a C file or within a C block of a C++ file:
It is a pointless if. It will call blah(), however the result of blah() is not considered by if at all. The only thing being considered is 5, thus the if will always evaluate to true. IOW you could write this code as
blah();
// do something
without any if at all.