Search code examples
c++structcompiler-errorscompiler-warnings

Compile time hints/warnings on struct changes


I have a basic POD struct with some fields

struct A{
    int a,
    int b,
};

The nature of my use case requires that these fields change every so often (like 1-2 months, regular but not often). This means that I want to check the field usages of the struct after the changes to make sure everything is still fine.

The compiler checks that all field usages are valid, something like a.c will fail at compile time.

However, some of my functions should access and handle ALL of the fields of A. So while the compiler verifies that all usages are valid, it doesn't validate that all the fields are used.

This work/checking must be done manually (if there is a way to do this at compile time, please enlighten me). So our current design tries to make this as easy as possible. We grouped most of the relevant functions into one folder/library so we could check over them in one place. However, some usages are embedded in private class functions that would honestly be more of a pain to refactor out into the common lib than the benefits it brings.

It's reasonable to just rely on documentation saying "Hey, after changing struct A, check the function foo in class FooThing". But I'm looking to see if we can get some type of compile time warnings.

My idea was to basically drop a static_assert next each relevant function that would check the size of A. Most changes should change the size, so an unchanged static_assert would fail at compile time, pointing me to the general area of the function. Then I could just change the function and the assert.

So besides the function foo for example, I would have something like static_assert(sizeof(A) == 16) or whatever size. This isn't foolproof, as it's possible that changes to struct might not change the total size, but I'm not looking for something really rigorous here, just something that could be helpful 90% of the time.

The main reason why this doesn't work for me is that int and other data types don't have a specified size from the standard. This is a problem for me since my project is cross platform.

In short, I am looking for a way to signal at compile time to check certain functions after a struct's definition has been changed.


Solution

  • One possibility is to put a version number into the struct itself, like so:

    struct A{
        int a;
        int b;
    
        static constexpr int major_version = 1;
    };
    

    Then, in calling code, you place assertions that check the value of the major version:

    void doSomething(A a)
    {
        static_assert(A::major_version == 1, "Unexpected A major version");
        // Do something with a
    }
    

    Then, any time you make an update to A that you think merits re-inspection of all calling code, you increment A::major_version, and then the static_assert will fire anywhere you haven't changed it.