Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ auto with multiple choices

Tags:

c++

c++11

During my adventures with project I realised that I can't use the advantage of the new c++11 auto keyword if I want to initialise the parameter depending on the condition.

Basically I had a code snippet like this:

auto foo = bar::getfoo();

Which needed to be change to:

FOO foo
if(cond){
   foo = bar::getfoo();
} else {
  foo = baz::getotherfoo();
}

But then I need to declare the foo with the type (as the compiler can't know that I will be using the same type return. I was wondering if there is any way of using the auto keyword in such case. The other solution which I came up with is using the ? : operator with such code:

auto foo = cond ? bar::getfoo() : baz::getotherfoo();

But if there is more then two functions to choose from I don't really want to chain the ? : operators. I am wondering if there is any good pattern to use in such case.

like image 546
cerkiewny Avatar asked May 20 '15 10:05

cerkiewny


3 Answers

Your instincts to use the ? : operator are correct - it's a good idea to initialise a variable only once and avoid the redundant default construction/assignment cycle.

A way to do this is to defer the selection of the Foo creation to a small utility function:

auto make_foo() -> decltype(bar::getfoo()) 
{
    if (condition1()) {
        return bar::getfoo();
    }
    else if(condition2()) {
        return baz::getfoo();
    }
    else {
        return banana::getfoo();
    }
}

void foo_test() {

    auto foo = make_foo();
}

Note that because of Return Value Optimisation, this is extremely efficient.

If you have c++14 it's even nicer - the make_foo() function can deduce its own return type:

auto make_foo() {
    if (condition1()) {
        return bar::getfoo();
    }
    else if(condition2()) {
        return baz::getfoo();
    }
    else {
        return banana::getfoo();
    }
}
like image 107
Richard Hodges Avatar answered Oct 14 '22 00:10

Richard Hodges


This is what decltype is for. It will provide you with the type of an expression, without actually evaluating (and you could implement auto in terms off):

decltype(bar::getfoo()) foo;
if (....) {foo = ...;} else {foo = ...;}
like image 5
Lanting Avatar answered Oct 14 '22 01:10

Lanting


auto a = foo();

constructs a from foo();

std::decay<decltype( foo() )>::type a;
if(cond){
  a = foo();
}else{
  a = bar();
}

default constructs a then assigns to it the result of foo() or bar() based on cond.

decay is needed as otherwise of foo() returns a reference or a const decltype will deduce the 'wrong' type for a.

auto a = [&]{
  if (cond)
    return foo();
  else
    return bar();
}();

uses a C++14 feature (that most C++11 compilers supported early on), but conditionally calls either foo or bar and constructs a from it. This logicalky requires an extra move, but the compiler will almost certainly elide it so it won't actually happen.

like image 4
Yakk - Adam Nevraumont Avatar answered Oct 14 '22 00:10

Yakk - Adam Nevraumont