kphp icon indicating copy to clipboard operation
kphp copied to clipboard

Fix `VertexAdaptor` comparison

Open mkornaukhov03 opened this issue 9 months ago • 0 comments

Some things about VertexAdaptor:

  • Comparison Operator Limitation: the comparison operator is defined only when there is a single template parameter.
  • Template Friends: this class utilizes template friends classes to itself.
  • Constructor/Assignment Operator Overloading: there is a constructor/assignment operator that takes the same class with a different template parameter.
  • Cross-Instance Comparison and Implicit Conversions: when comparing two instances of the class with different template parameters, one instance is implicitly converted to the other. The intention is to use a hierarchy of casting defined by op_type_is_base_of. However, the static_assert does not establish the conversion algorithm, leading the compiler to consider that any class with any template parameter can be converted to the same class with any other template parameter. The intended behavior is to allow comparisons only between direct base classes (determined by the op_type_is_base_of constexpr function). To achieve this, SFINAE with std::enable_if can be employed.

A small minimal reproducer of a problem is here:

#include <iostream>

enum Operation {
    op_universal,
    op_bin,
    op_seq,
    op_unary,
};

constexpr bool is_base_of(Operation a, Operation b) {
    return a == op_universal;
}

template<Operation Op1>
class A {
  int *impl_;
  template<Operation Op2>
  friend class A;
public:
  // template<Operation FromOp, typename = std::enable_if_t<is_base_of(Op1, FromOp)>>
  template<Operation FromOp>
  A(const A<FromOp> &from) noexcept
    : impl_(from.impl_) {
    // before here was static assert is_base_of(Op1, FromOp)
  }

  // template<Operation FromOp, typename = std::enable_if_t<is_base_of(Op1, FromOp)>>
  template<Operation FromOp>
  A<Op1> &operator=(const A<FromOp> &from) noexcept {
    // before here was static assert is_base_of(Op1, FromOp)
    impl_ = from.impl_;
    return *this;
  }
  explicit A(int * impl) : impl_(impl) {}

  bool operator==(const A<Op1> &other) const noexcept {
    return impl_ == other.impl_;
  }
};

int main() {
    A<op_seq> x(new int(32));
    A<op_universal> y(new int(123));

    if (x == y) {
        std::cout << "Eq!\n";
    }
}

With C++17 it's compilable using both clang and gcc. But with C++20 it's compilable only with gcc. This fix allows to compile kphp2cpp target using C++20 and clang compiler.

mkornaukhov03 avatar May 07 '24 10:05 mkornaukhov03