Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C++ lambda functions during variable initialisation

Tags:

c++

c++11

lambda

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(); });
}();
like image 846
Tomaka17 Avatar asked Aug 09 '10 10:08

Tomaka17


1 Answers

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;
}
like image 137
Daniel Earwicker Avatar answered Oct 07 '22 23:10

Daniel Earwicker