tags:

views:

150

answers:

3

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(); });
}();
+1  A: 

Is there anything wrong with this code that I didn't see?

Yes : bar isn't declared.

Do you find it better than the one above?

Your previous code is less complexe, I don't see the point to use lambda in this very case. However your second code could be useful in a case where you reused the lambda and called it several times.

In fact, in this type of case, I would have used a named function with the switch inside. That way you name the choice being made.

g++ seems to inline the function, but do you think that all compilers will do so?

How could we know? Each compiler is free to apply some kind of optimizations where they seem useful. Inlining is one kind of optimization that is done by compilers where it's useful.

I guess that If you would have use a variable to keep your lambda somewhere for several call, it would have generate a functor class for it (local or not) instead of inlining the code.

Klaim
Meh. Whether `bar` is declared or not is not the main point.
KennyTM
+2  A: 

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;
}
Daniel Earwicker
Thanks, I'm not so used to using functional languages
Tomaka17
A: 

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;
ronag