Skip to content

Match

Description

Open a match over x. The scrutinee is copied by value (so rvalues / function returns work); each When arm binds it (or, for a variant, its payload) to a name you give. Pair with When arms and an optional trailing Otherwise. Arms are mutually exclusive; the block runs at most one of them.

For a static match the selector is a _Generic constant, so exactly one arm is live per instantiation and the construct folds to it; the others are dead but must still compile against the value’s static type. This makes the static form meaningful inside generic/macro code, and free everywhere else.

Usage example (from documentation)

  Match(value) {
      When(int, n)    WriteFmtLn("int {}", n);
      When(double, d) WriteFmtLn("double {}", d);
      Otherwise       WriteFmtLn("other");
  }

Success

Runs the body of the single matching arm (or Otherwise if none), with that arm’s named binding in scope. Block exits after one arm.

Failure

If no When matches and there is no Otherwise, the match is non-exhaustive and aborts via LOG_FATAL – it never silently falls through. A When body that misuses its binding’s type is a compile error (every arm is type-checked).

Usage example (Cross-references)

Usage examples (Cross-references)
    #define Match(x)                                                                                                       \
        for (bool MisraMatched = false, UNPL(tm_once) = true; UNPL(tm_once); UNPL(tm_once) = false,                        \
                  ASSERT_OR_FATAL(MisraMatched, "Match: no arm matched and no Otherwise (non-exhaustive)"))                \
            for (TYPE_OF(x) MisraSubject = (x), *UNPL(tm_loop) = &MisraSubject; UNPL(tm_loop); UNPL(tm_loop) = NULL)
        Number n   = Number_from_int(42);
        bool   hit = false;
        Match(n) {
            When(Number, int, v) hit    = (v == 42);
            When(Number, double, v) hit = false;
        Number m  = Number_from_double(2.5);
        bool   hd = false;
        Match(m) {
            When(Number, int, v) hd    = false;
            When(Number, double, v) hd = (v == 2.5);
        int    ai = 0;
        double bd = 0.0;
        Match(a) {
            When(Number, int, n) ai    = n * 2; // n : int
            When(Number, double, r) bd = r;
            When(Number, double, r) bd = r;
        }
        Match(b) {
            When(Number, int, n) ai    = n;
            When(Number, double, r) bd = r * 2.0; // r : double
    // value in, value out -- no pointers
    static Number twice(Number n) {
        Match(n) {
            When(Number, int, v) return Number_from_int(v * 2);
            When(Number, double, v) return Number_from_double(v * 2.0);
        Number r  = twice(Number_from_int(21));
        bool   ok = false;
        Match(r) {
            When(Number, int, v) ok    = (v == 42);
            When(Number, double, v) ok = false;
        bool ok = false;
        // Match directly on a function-return rvalue.
        Match(twice(Number_from_double(1.5))) {
            When(Number, int, v) ok    = false;
            When(Number, double, v) ok = (v == 3.0);
        Cell c  = Cell_from_char('Z');
        bool ok = false;
        Match(c) {
            When(Cell, int, v) ok  = false;
            When(Cell, char, v) ok = (v == 'Z');
        bool ok     = true;
        for (int k = 0; k < 3; k++) {
            Match(vals[k]) {
                When(Tri, int, v) ok = ok && (v == 7), seen |= 1;
                When(Tri, float, v) ok = ok && (v == 1.5f), seen |= 2;
        Number n     = Number_from_int(7);
        int    count = 0;
        Match(n) {
            When(Number, int, v) count++;
            When(Number, double, v) count++;
    bool deadend_variant_nonexhaustive(void) {
        Number n = Number_from_double(9.0); // holds double, only int handled, no Otherwise
        Match(n) {
            When(Number, int, v)(void) v;
        }
    
        int tag = -1;
        Match(i) {
            When(int, v) tag    = 0;
            When(double, v) tag = 1;
        bool ok = tag == 0;
    
        Match(d) {
            When(int, v) tag    = 0;
            When(double, v) tag = 1;
    
        // Unlisted type falls to Otherwise.
        Match(p) {
            When(int, v) tag    = 0;
            When(double, v) tag = 1;
        int    ri = 0;
        double rd = 0.0;
        Match(i) {
            When(int, n) ri    = n * 2;
            When(double, x) rd = x;
            When(double, x) rd = x;
        }
        Match(d) {
            When(int, n) ri    = n;
            When(double, x) rd = x * 2.0;
        bool hit = false;
        // Scrutinee is an rvalue; copied by value, then bound to `n`.
        Match(i + 1) {
            When(int, n) hit    = (n == 5);
            When(double, x) hit = false;
        int i     = 7;
        int count = 0;
        Match(i) {
            When(int, v) count++;
            When(double, v) count++;
        Position2D p   = {1.0f, 2.0f};
        bool       hit = false;
        Match(p) {
            When(int, v) hit    = false;
            When(double, v) hit = false;
        int    oi = 0;
        double id = 0.0;
        Match(i) {
            When(int, outer) {
                Match(d) {
        Match(i) {
            When(int, outer) {
                Match(d) {
                    When(int, x) id    = -1.0;
                    When(double, x) id = x; // inner bind : double
    bool deadend_match_nonexhaustive(void) {
        Position2D p = {1.0f, 2.0f};
        Match(p) {
            When(int, v)(void) v; // never matches Position2D, and there is no Otherwise
        }
Last updated on