【问题标题】:template friend bool overload clash in namespace命名空间中的模板朋友布尔重载冲突
【发布时间】:2021-01-18 15:02:53
【问题描述】:

我在同一个命名空间 xy 和 rgba 中有 2 个不同的类模板。它们都重载了运算符 == 和 !=。当我编译时,我得到了已经定义了重载的错误。是因为这两个类都在同一个命名空间中吗?如果是这样,是否有避免冲突的技巧?我为模板尝试了不同的标签,它给了我相同的结果。

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);
    }
};

【问题讨论】:

  • 为什么您的比较运算符是模板化的?更不用说对任何类型的隐式转换了。
  • template&lt;typename B&gt; operatorB() 基本上指定这个类型可以转换为已知宇宙中的任何其他类型。这种超载只会以眼泪收场。
  • 这是一个猜测,但我认为您正在寻找前向声明,而不是模板。
  • friend 声明声明了类外部的函数。你做两次。那么,为什么要friend
  • @cigien 我正在使用我想使用原生向量的库。山姆是的,这就是想法:D。谢谢 Serge,你成功了

标签: c++ overloading friend


【解决方案1】:

评论里有很多好点,所以我只为你的编译问题提供一个解决方案。

您需要一些type_traitsif 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

两个类是同一个函数的友元,函数只在类外声明一次。

然后在运算符内部,我们在编译时选择是否可以比较 en x/yr/g/b/a

【讨论】:

  • 哇,谢谢马丁,c'est 完成了! Je comprends rien, un bon challenge du coup :D
猜你喜欢
  • 2018-10-20
  • 2018-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 2010-09-20
相关资源
最近更新 更多