The canonical way to do static branch prediction is that if is predicted not-branched (i.e. every if clause is executed, not else), and loops and backward-gotos are taken. So, don't put the common case in else if you expect static prediction to be significant. Getting around an untaken loop isn't as easy; I've never tried but I suppose putting it an an else clause should work pretty portably.
Many compilers support some form of #pragma unroll, but it will still be necessary to guard it with some kind of #if to protect other compilers.
Branch prediction hints can theoretically express a complete description of how to transform a program's flow-control graph and arrange the basic blocks in executable memory… so there are a variety of things to express, and most won't be very portable.
As GNU recommends in the documentation for __builtin_expect, profile-guided optimization is superior to hints, and with less effort.
if? Likeif([[unlikely]] unlikely_condition) { ... }? Currently the syntax does not allow it. It does however allowif([[unlikely]] bool b = ...) { }. Maybe one could abuse that :)if(likely(...))junk in completely non-performance-critical code, and IMO this is really bad. For one thing, it doesn't read naturally in English - it sounds like "if this condition is likely to be true" instead of "if this condition is true, which it likely is". And for another, it's just clutter. Unless you have lots of performance-critical conditionals that won't compile tocmovor similar already, just ignore branch prediction hinting.if(unlikely(...)). They prefer early exits that make code flow easier to follow. If they did not do this then the static branch prediction would always fail.