c++boostc++17aggregate-initialization

Is there a way to use boost::equality_comparable with aggregates without messing up the initialization syntax?


I have some aggregate structs like this:

#include <boost/operators.hpp>

struct Agg /*: boost::equality_comparable<Agg> */{  // when I uncomment this
    int i{};
    int j{};
    friend bool operator==(const Agg&, const Agg&) { return true; }
};

int main() {
    return Agg{/*{},*/ 1}.i; // I also need to uncomment this
}

https://godbolt.org/z/zhre4Wv7E

I would like to add operator!= to them and wanted to use boost::equality_comparable to do that.

But now I cannot instantiate them any more unless I add an additional pair of empty braces (to initialize the base class) to all usage sites, which would be a breaking change and not worth it.

Is there anything I can do about this except write my own operator!=?


Solution

  • Prior to C++17 you could not use aggregate initialization at all with a class that uses inheritance. In C++17 you can, but the trade-off is that have to use aggregate initialization of the base class as the first item in the curly braces. Now, the boost class you are inheriting doesn't have any members, but you still have to provide the empty set of curly braces as a placeholder for the base class.

    There are a few options you have, with various trade-offs.

    You can implement your own operator!= as you observed. For a single class where operator != can be implemented in terms of ! operator==() I would probably go that route.

    As Sehe suggests in another answer if you can move to C++20, the spaceship operator is more flexible and gives you what you need.

    You could also just implement a constructor that receives i and j. This wouldn't be aggregate initialization, but the syntax would simulate it syntactically unless you like the possibility of members being uninitialized. In C++17 this would be very nearly transparent. In C++20 or later you would lose designated initialize syntax if you go this route.

    struct Agg : boost::equality_comparable<Agg> {  // when I uncomment this
        Agg (int i=0, int j=0) : i(i), j(j){}
        int i{};
        int j{};
        friend bool operator==(const Agg&, const Agg&) { return true; }
    };
    
    
    int main() {
        Agg agg1 = {1, 2};
        Agg agg2 { 1, 2 };
        Agg agg3;
        Agg agg4 = {1};
    }