名称空间中的模板朋友布尔重载冲突
template friend bool overload clash in namespace
我在同一个命名空间 xy 和 rgba 中有 2 个不同的 class 模板。它们都重载运算符 == 和 !=。当我编译时,我得到了重载已经被定义的错误。是因为这两个 classes 都在同一个命名空间中吗?如果是这样,是否有避免冲突的技巧?我为模板尝试了不同的标签,它给了我相同的结果。
template <typename A>
class xy
{
public:
A x, y;
xy() :x(0), y(0) {}
xy(A x, A y) :x(x), y(y) {}
template<typename B>
xy& operator = (const B& v) {
x = A(v.x), y = A(v.y); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v) {
return a.x == v.x && a.y == v.y;
}
template<typename B, typename C>
friend bool operator != (const B& a, const C& v) {
return a.x != v.x || a.y != v.y;
}
template<typename B>
operator B() const {
return B(x, y);
}
};
class rgba
{
public:
int r, g, b, a;
rgba() :r(255), g(255), b(255), a(255) {}
rgba(int r, int g, int b, int a) :r(r), g(g), b(b), a(a) {}
template<typename B>
rgba& operator = (const B& v) {
r = A(v.r), g = A(v.g), r = A(v.b), a = A(v.a); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v) { // <- already defined ?
return a.r == v.r && a.g == v.g && a.b == v.b && a.a == v.a;
}
template<typename B, typename C>
friend bool operator != (const B& a, const C& v) { // <- already defined ?
return a.r != v.r || a.g != v.g || a.b != v.b || a.a != v.a;
}
template<typename B>
operator B() const {
return B(r, g, b, a);
}
};
评论中有很多好点,所以我只提供一个解决你编译问题的方法。
您需要一些 type_traits
和 if constexpr
。如果你没有 c++17
你可以用 SFINAE
.
#include <iostream>
#include <type_traits>
template <class T, class U = void>
struct has_xy : std::false_type{};
template <class T>
struct has_xy<T, std::void_t<
decltype(std::declval<T>().x),
decltype(std::declval<T>().y)
>
>: std::true_type{};
template <class T, class U = void>
struct has_rgba : std::false_type{};
template <class T>
struct has_rgba<T, std::void_t<
decltype(std::declval<T>().r),
decltype(std::declval<T>().g),
decltype(std::declval<T>().b),
decltype(std::declval<T>().a)
>
>: std::true_type{};
template <typename A>
class xy
{
public:
A x, y;
xy() :x(0), y(0) {}
xy(A x, A y) :x(x), y(y) {}
template<typename B>
xy& operator = (const B& v) {
x = A(v.x), y = A(v.y); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v);
template<typename B, typename C>
friend bool operator != (const B& a, const C& v);
template<typename B>
operator B() const {
return B(x, y);
}
};
class rgba
{
public:
int r, g, b, a;
rgba() :r(255), g(255), b(255), a(255) {}
rgba(int r, int g, int b, int a) :r(r), g(g), b(b), a(a) {}
template<typename B>
rgba& operator = (const B& v) {
r = A(v.r), g = A(v.g), r = A(v.b), a = A(v.a); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v);
template<typename B, typename C>
friend bool operator != (const B& a, const C& v);
template<typename B>
operator B() const {
return B(r, g, b, a);
}
};
template<typename B, typename C>
bool operator == (const B& a, const C& v)
{
if constexpr ( has_xy<B>::value and has_xy<C>::value )
{
return a.x == v.x && a.y == v.y;
}
else if constexpr ( has_rgba<B>::value and has_rgba<C>::value )
{
return a.r == v.r && a.g == v.g && a.b == v.b && a.a == v.a;
}
else
{
return false; // or throw, or don't compile do as you want
}
}
template<typename B, typename C>
bool operator != (const B& a, const C& v)
{
return not operator==(a,v);
}
int main()
{
xy<float> x1,x2;
rgba r1,r2;
if ( x1 == x2 ) { std::cout << " x1 == x2 " << std::endl; }
if ( x1 != x2 ) { std::cout << " x1 != x2 " << std::endl; }
if ( r1 == r2 ) { std::cout << " r1 == r2 " << std::endl; }
if ( r1 != r2 ) { std::cout << " r1 != r2 " << std::endl; }
if ( x1 == r2 ) { std::cout << " x1 == r2 " << std::endl; }
if ( x1 != r2 ) { std::cout << " x1 != r2 " << std::endl; }
}
现场演示:wandbox
两个 class 是具有相同功能的朋友,并且该功能仅在 class 之外声明一次。
然后在运算符内部,我们select,在编译时,如果我们可以比较en x/y
or on r/g/b/a
我在同一个命名空间 xy 和 rgba 中有 2 个不同的 class 模板。它们都重载运算符 == 和 !=。当我编译时,我得到了重载已经被定义的错误。是因为这两个 classes 都在同一个命名空间中吗?如果是这样,是否有避免冲突的技巧?我为模板尝试了不同的标签,它给了我相同的结果。
template <typename A>
class xy
{
public:
A x, y;
xy() :x(0), y(0) {}
xy(A x, A y) :x(x), y(y) {}
template<typename B>
xy& operator = (const B& v) {
x = A(v.x), y = A(v.y); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v) {
return a.x == v.x && a.y == v.y;
}
template<typename B, typename C>
friend bool operator != (const B& a, const C& v) {
return a.x != v.x || a.y != v.y;
}
template<typename B>
operator B() const {
return B(x, y);
}
};
class rgba
{
public:
int r, g, b, a;
rgba() :r(255), g(255), b(255), a(255) {}
rgba(int r, int g, int b, int a) :r(r), g(g), b(b), a(a) {}
template<typename B>
rgba& operator = (const B& v) {
r = A(v.r), g = A(v.g), r = A(v.b), a = A(v.a); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v) { // <- already defined ?
return a.r == v.r && a.g == v.g && a.b == v.b && a.a == v.a;
}
template<typename B, typename C>
friend bool operator != (const B& a, const C& v) { // <- already defined ?
return a.r != v.r || a.g != v.g || a.b != v.b || a.a != v.a;
}
template<typename B>
operator B() const {
return B(r, g, b, a);
}
};
评论中有很多好点,所以我只提供一个解决你编译问题的方法。
您需要一些 type_traits
和 if constexpr
。如果你没有 c++17
你可以用 SFINAE
.
#include <iostream>
#include <type_traits>
template <class T, class U = void>
struct has_xy : std::false_type{};
template <class T>
struct has_xy<T, std::void_t<
decltype(std::declval<T>().x),
decltype(std::declval<T>().y)
>
>: std::true_type{};
template <class T, class U = void>
struct has_rgba : std::false_type{};
template <class T>
struct has_rgba<T, std::void_t<
decltype(std::declval<T>().r),
decltype(std::declval<T>().g),
decltype(std::declval<T>().b),
decltype(std::declval<T>().a)
>
>: std::true_type{};
template <typename A>
class xy
{
public:
A x, y;
xy() :x(0), y(0) {}
xy(A x, A y) :x(x), y(y) {}
template<typename B>
xy& operator = (const B& v) {
x = A(v.x), y = A(v.y); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v);
template<typename B, typename C>
friend bool operator != (const B& a, const C& v);
template<typename B>
operator B() const {
return B(x, y);
}
};
class rgba
{
public:
int r, g, b, a;
rgba() :r(255), g(255), b(255), a(255) {}
rgba(int r, int g, int b, int a) :r(r), g(g), b(b), a(a) {}
template<typename B>
rgba& operator = (const B& v) {
r = A(v.r), g = A(v.g), r = A(v.b), a = A(v.a); return*this;
}
template<typename B, typename C>
friend bool operator == (const B& a, const C& v);
template<typename B, typename C>
friend bool operator != (const B& a, const C& v);
template<typename B>
operator B() const {
return B(r, g, b, a);
}
};
template<typename B, typename C>
bool operator == (const B& a, const C& v)
{
if constexpr ( has_xy<B>::value and has_xy<C>::value )
{
return a.x == v.x && a.y == v.y;
}
else if constexpr ( has_rgba<B>::value and has_rgba<C>::value )
{
return a.r == v.r && a.g == v.g && a.b == v.b && a.a == v.a;
}
else
{
return false; // or throw, or don't compile do as you want
}
}
template<typename B, typename C>
bool operator != (const B& a, const C& v)
{
return not operator==(a,v);
}
int main()
{
xy<float> x1,x2;
rgba r1,r2;
if ( x1 == x2 ) { std::cout << " x1 == x2 " << std::endl; }
if ( x1 != x2 ) { std::cout << " x1 != x2 " << std::endl; }
if ( r1 == r2 ) { std::cout << " r1 == r2 " << std::endl; }
if ( r1 != r2 ) { std::cout << " r1 != r2 " << std::endl; }
if ( x1 == r2 ) { std::cout << " x1 == r2 " << std::endl; }
if ( x1 != r2 ) { std::cout << " x1 != r2 " << std::endl; }
}
现场演示:wandbox
两个 class 是具有相同功能的朋友,并且该功能仅在 class 之外声明一次。
然后在运算符内部,我们select,在编译时,如果我们可以比较en x/y
or on r/g/b/a