Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a generic way to make a tuple out of all class attributes?

Tags:

c++

I have many classes that use std::tie to make a tuple out of all the class attribute and use it to implement the == operator. They look like this:

class S
{
    int number;
    std::string text;
    // and many other attributes...
    
    auto tied() const noexcept { return std::tie(/* list all attributes here */); }
    
    bool operator==(const S &o) const noexcept
    {
        return tied() == o.tied();
    }
};

The classes have similar methods but very different attributes, so I want to create a base class they all inherit from and I want to include this bit of comparison in the base class.

However, since I can't define a virtual method returning auto, I'm struggling to write an abstract generic tied() method that should make a tuple out of all a derived class's attributes no matter how many of them or of which types they are.

Is this feasible?

Note: All attributes are either of trivial type or std::strings.

like image 707
Haythem Avatar asked Feb 02 '26 10:02

Haythem


1 Answers

If there is a bounded number of elements, you can use CRTP and https://stackoverflow.com/a/39779537/1774667 to find the number of elements.

Using structured binding you can then build a tuple out of them.

This can be written in the CRTP base.

template<class T>
struct implement_equals {
  friend bool operator!=(implement_equals const& lhs, implement_equals const& rhs ) {
    return !(lhs==rhs);
  }
  T const& self() const {
    return *static_cast<T const*>(this);
  }
  friend bool operator==(implement_equals const& lhs, implement_equals const& rhs) {
    constexpr std::size_t count = construct_airity<T>;
    return make_tie_from<count>{}(lhs.self()) == make_tie_from<count>{}(rhs.self());
  }
};

next write make_tuple_from.

template<std::size_t>
struct make_tie_from;

template<>
struct make_tie_from<1> {
  template<class T>
  auto operator()( T const& t ) const {
    auto const&[e0] = t;
    return std::tie(e0);
  }
};

then write 20 of those.

There are libraries that do this already for you you can find with a bit of googling. None of them are perfect, and they all require that the thing you are making a tie of expose the data publicly.

If you want to hide that data, create a struct that contains the data publicly to get the tie, and expose some way for implement_equals to get access to that struct (friend, whatever).


In c++14 you cannot do even this crippled for of reflection.

You can write implement_equals, but you have to manually write the tie. It is better than a virtual function, however.

like image 99
Yakk - Adam Nevraumont Avatar answered Feb 04 '26 00:02

Yakk - Adam Nevraumont



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!