ARTICLE AD BOX
I have the following classes adapted from the section "Adapter versus policy" page 515 of "Hands-on Design Patterns with C++":
a Value class with basic operations
decorators/adapters to make the underlying Value comparable with equality and/or addable.
All the template magic is needed because a class like Ordered<Addable<Value<int>>> needs to have operator+ returning Ordered<Addable<Value<int>>> and not just Addable<Value<int>>.
#include <iostream> template <typename T> class Value { public: using basic_type = T; using value_type = Value; template <typename FT> using rebind = Value; explicit Value() = default; explicit Value(basic_type v) : m_val {v} {} Value(Value const&) = default; Value& operator=(Value const&) = default; Value& operator=(basic_type rhs) { m_val = rhs; return *this; } friend std::ostream& operator<<(std::ostream& out, Value x) { out << x.m_val; return out; } protected: T m_val {}; }; template <typename T, typename FT = void> class Ordered : public T::template rebind<FT> { using base_type = typename T::template rebind<FT>; public: using base_type::base_type; using base_type::operator=; template <typename FV> using rebind = Ordered<T, FV>; using value_type = typename base_type::value_type; using basic_type = typename value_type::basic_type; Ordered(value_type v) : base_type {v} {} bool operator==(FT rhs) { return this->m_val == rhs.m_val; } bool operator==(basic_type rhs) { return this->m_val < rhs; } friend bool operator==(basic_type lhs, FT rhs) { return rhs == lhs; } }; template <typename T> class Ordered<T, void> : public T::template rebind<Ordered<T, void>> { using base_type = typename T::template rebind<Ordered>; public: using base_type::base_type; using base_type::operator=; template <typename FV> using rebind = Ordered<T, FV>; using value_type = typename base_type::value_type; using basic_type = typename value_type::basic_type; Ordered(value_type v) : base_type {v} {} bool operator==(Ordered rhs) { return this->m_val == rhs.m_val; } bool operator==(basic_type rhs) { return this->m_val == rhs; } friend bool operator==(basic_type lhs, Ordered rhs) { return rhs == lhs; } }; template <typename T, typename FT = void> class Addable : public T::template rebind<FT> { using base_type = typename T::template rebind<FT>; public: using base_type::base_type; using base_type::operator=; template <typename FV> using rebind = Addable<T, FV>; using value_type = typename base_type::value_type; using basic_type = typename value_type::basic_type; Addable(value_type v) : base_type {v} {} FT operator+(FT rhs) { return FT {this->m_val + rhs.m_val}; } FT operator+(basic_type rhs) { return FT {this->m_val + rhs}; } friend FT operator+(basic_type lhs, FT rhs) { return rhs + lhs; } }; template <typename T> class Addable<T, void> : public T::template rebind<Addable<T, void>> { using base_type = typename T::template rebind<Addable>; public: using base_type::base_type; using base_type::operator=; template <typename FV> using rebind = Addable<T, FV>; using value_type = typename base_type::value_type; using basic_type = typename value_type::basic_type; Addable(value_type v) : T {v} {} Addable operator+(Addable rhs) { return Addable {this->m_val + rhs.m_val}; } Addable operator+(basic_type rhs) { return Addable {this->m_val + rhs}; } friend Addable operator+(basic_type lhs, Addable rhs) { return Addable {lhs + rhs.m_val}; } }; int main() { using Type = Addable<Ordered<Value<int>>>; Type a {5}, b {3}, c{7}; if (c + 1 == a + b) { std::cout << "equality" << std::endl; } }The issue I'm observing is that compiling with GCC 15.2.1 with -std=c++20 runs into the following warning:
$ g++ adapter.cpp -std=c++20 adapter.cpp: In function ‘int main()’: adapter.cpp:127:26: warning: C++20 says that these are ambiguous, even though the second is reversed: 127 | if (c + 1 == a + b) { | ^ adapter.cpp:40:14: note: candidate 1: ‘bool Ordered<T, FT>::operator==(FT) [with T = Value<int>; FT = Addable<Ordered<Value<int> > >]’ 40 | bool operator==(FT rhs) { | ^~~~~~~~ adapter.cpp:40:14: note: candidate 2: ‘bool Ordered<T, FT>::operator==(FT) [with T = Value<int>; FT = Addable<Ordered<Value<int> > >]’ (reversed)Could you help me understand why that warning happens?
Btw, if the Type = Ordered<Addable<Value<int>>> in main, the code compiles without warning.
