Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ ternary assignment of lambda

Any idea why the following snippet doesn't compile? It complains with an error "error: operands to ?: have different types"

  auto lambda1 = [&](T& arg) {
      ...
  };
  auto lambda2 = [&](T& arg) {
      ...
  };
  auto lambda = condition ? lambda1 : lambda2;
like image 534
cow Avatar asked Nov 06 '19 17:11

cow


People also ask

Can we use ternary operator in lambda expression?

use of ternary operator in lambda expression gives incorrect results.

Can we assign value in ternary operator in C?

You can use the ternary operator to assign references & const values where you would otherwise need to write a function to handle it: int getMyValue() { if( myCondition ) return 42; else return 314; } const int myValue = getMyValue();

Can we use assignment operator in ternary operator?

both are fine. invalid lvalue in assignment. which gives error since in C(not in C++) ternary operator cannot return lvalue.

Is ternary faster than if-else C?

It is not faster. There is one difference when you can initialize a constant variable depending on some expression: const int x = (a<b) ?


1 Answers

Individual lambdas are translated to different classes by the compiler. For example, lambda1's definition is equivalent to:

class SomeCompilerGeneratedTypeName {
public:
  SomeCompilerGeneratedTypeName(...) { // Capture all the required variables here
  }

  void operator()(T& arg) const {
    // ...
  }

private:
  // All the captured variables here ...
};

Therefore, two different types are generated by the compiler, which causes a type incompatibility for auto lambda = condition ? lambda1 : lambda2;

The following would work:

auto lambda = condition ? std::function<void(T&)>(lambda1) : std::function<void(T&)>(lambda2);

To highlight that both lambdas are indeed different types, we can use <typeinfo> from the standard library and the typeid operator. Lambdas are not polymorphic types, so the standard guarantees that the 'typeid' operator is evaluated at compile time. This shows that the following example is valid even if RTTI is disabled:

#include <iostream>
#include <typeinfo>

int main()
{
    struct T {

    };

    auto lambda1 = [&](T& arg) {
        return;
    };

    auto lambda2 = [&](T& arg) {
      return;
    };

    std::cout << typeid(lambda1).name() << "/" << typeid(lambda1).hash_code() << std::endl;
    std::cout << typeid(lambda2).name() << "/" << typeid(lambda2).hash_code() << std::endl;

    return 0;
}

The output of the program is (with GCC 8.3, see on Gobolt):

Z4mainEUlRZ4mainE1TE_/7654536205164302515
Z4mainEUlRZ4mainE1TE0_/10614161759544824066
like image 74
Xatyrian Avatar answered Oct 24 '22 00:10

Xatyrian