Emulating __uint128_t
Will anything behave unexpectedly with this code?

For that to answer we would need the expectations. Most users will expect a number type to behave like the ints do.

What does that mean in your example?


your type should be usable in an if(number) (this also includes if(!number))
your type should be comparable with other int types, nobody wants to write number == board_t{0, 3} instead of number == 3  (this probably means you should write an implicit conversion from int to board_t


Surely there are other things you need to mimic from the ints.

Do I need to create a constructor? Is the usage of the {} struct initializer good form?

Given the fact that you should provide something like board_t(int) you will need to provide the other constructors as well. 

Internal functions (that know about the internal format of board_t might use the "struct initialize" but in general I would avoid it as it introduces dependencies on the inner layout.

Do I need to override the assignment operator?

No, the default generated one will simply call the assignments on the members as well which is fine.

Are there other ways to improve this code, style, correctness and speed?

Yes:


why is the type called board_t?
if the user should be able to supply values you could generate an own literal for this purpose
define binary operators like operator+ outside the class to get "more symmetric" code (this makes both operands eligible for automatic conversions instead of only the right hand side)
the previous point may also be applied for unary operators that don't change the internal representation of the object (like operator~())


All in all your design should be:

If the platform supports uint128 the type should only be an alias of it and if it does not support this type, then your class should behave as much as uint128 as possible (so on platforms that support it your code should do the same for both "implementations").