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 needs to have operator+ returning Ordered and not just Addable.
#include
template
class Value
{
public:
using basic_type = T;
using value_type = Value;
template 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
class Ordered : public T::template rebind
{
using base_type = typename T::template rebind;
public:
using base_type::base_type;
using base_type::operator=;
template using rebind = Ordered;
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
class Ordered : public T::template rebind>
{
using base_type = typename T::template rebind;
public:
using base_type::base_type;
using base_type::operator=;
template using rebind = Ordered;
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
class Addable : public T::template rebind
{
using base_type = typename T::template rebind;
public:
using base_type::base_type;
using base_type::operator=;
template using rebind = Addable;
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
class Addable : public T::template rebind>
{
using base_type = typename T::template rebind;
public:
using base_type::base_type;
using base_type::operator=;
template using rebind = Addable;
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};
}
};
The issue I'm observing is that compiling with GCC 15.2.1 with -std=c++20 and the following main:
int main()
{
using Type = Addable>>;
Type a {5}, b {3}, c{7};
if (c + 1 == a + b) {
std::cout << "equality" << std::endl;
}
}
runs into the following warning:
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::operator==(FT) [with T = Value; FT = Addable > >]’
40 | bool operator==(FT rhs) {
| ^~~~~~~~
adapter.cpp:40:14: note: candidate 2: ‘bool Ordered::operator==(FT) [with T = Value; FT = Addable > >]’ (reversed)
~/Desktop/cpp_learning
Could you help me understand why that warning happens?
Btw, if the Type = Ordered in main, the code compiles without warning.