7

我正在尝试重载一个乘法运算符,但不想输入多个重载函数以考虑乘以 int 和 float、int 和 double、float 和 int 等...我希望编写一个重载运算符来解释与浮点数、整数和双精度数相乘的所有组合,并获得正确的返回类型。我收到错误消息,说没有找到采用“Widget::Widget”类型的右手操作数的运算符(或者没有可接受的转换)。我认为这是因为我使用 decltype 来设置返回对象 Widget 的模板类型。如果返回不是模板对象,则使用尾随返回类型有效。

这是我尝试制作的重载运算符的示例:

template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge) -> Widget<decltype(aWidge.x*bWidge.x)>
{
    Widget<decltype(aWidge.x*bWidge.x)> result;

    //do stuff needed when multiplying two Widgets

    return result;
}

template<typename T>
Widget<T>& Widget<T>::operator=(const Widget<T>& aWidget)
{
    x = aWidget.x;

    return *this;
}

这是模板类的示例

template<typename T> class Widget
{
    private:
        T x;
    public:
        Widget();
        ~Widget();
        void SetX(T value);
        Widget<T>& operator=(const Widget<T>& aWidget);
}

示例 Main.cpp

int main()
{
    Widget<int> aWidge;
    Widget<float> bWidge;
    Widget<float> cWidge;

    aWidge.SetX(2);
    bWidge.SetX(2.0);

    cWidge = aWidge*bWidge; //this should give a float return type
}
4

2 回答 2

5

仔细阅读错误信息,问题很明显:

candidate template ignored: substitution failure [with T1 = int, T2 = float]: 'x' is
      a private member of 'Widget<int>'

非成员二进制文件operator*试图x在其声明(和定义)中访问私有成员。由于您有一个 setter 函数,一个简单的解决方案是还定义一个 getter 并且只能x通过此函数访问成员:

template<typename T> class Widget
{
    private:
        T x;

    public:
        Widget() {}
        ~Widget() {}
        void SetX(T value) {}
        T& GetX() { return x; }
        const T& GetX() const { return x; }
        Widget<T>& operator=(const Widget<T>& aWidget);
};

template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.GetX()*bWidge.GetX())>
{
    Widget<decltype(aWidge.GetX()*bWidge.GetX())> result;
    //...
    return result;
}

另一种选择是operator*交朋友:

template<typename T> class Widget
{
    private:
        T x;

    template<typename T1, typename T2>
    friend auto
    operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
    -> Widget<decltype(aWidge.x*bWidge.x)>;

    public:
        Widget() {}
        ~Widget() {}
        void SetX(T value) {}
        Widget<T>& operator=(const Widget<T>& aWidget);
};

template<typename T1, typename T2>
auto
operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge)
-> Widget<decltype(aWidge.x*bWidge.x)>
{
    Widget<decltype(aWidge.x*bWidge.x)> result;

    return result;
}

或者,使其成为成员函数(感谢 WhozCraig)。

您可能还需要

typename std::decay<decltype(aWidge.x*bWidge.x)>::type

而不仅仅是decltype(aWidge.x*bWidge.x).

其他选项是

typename std::decay<decltype(std::declval<T1>()*std::declval<T2>())>::type

它完全绕过了前面的问题(感谢亚当),或者只是

typename std::common_type<T1, T2>::type

这应该适合这个目的,可以说是最简单的形式。

于 2014-04-15T23:37:41.237 回答
3

视觉工作室 2012

不要介意草率的代码。这是对一开始就无法正确编译的代码的快速修复(不要介意自动 decltype 问题)。

template<typename T>
class Widget
{
public:
    T x;
public:
    Widget()
        : x(666)
    {}

    ~Widget() {}

    void SetX(T value)
    {
        x = value;
    }

    Widget<T>& operator=(const Widget<T>& aWidget)
    {
        x = aWidget.x;

        return *this;
    }
};


template<typename T1, typename T2>
auto operator*(const Widget<T1>& aWidge, const Widget<T2>& bWidge) -> Widget<typename std::remove_const<decltype(aWidge.x*bWidge.x)>::type>
{
    Widget<typename std::remove_const<decltype(aWidge.x*bWidge.x)>::type> result;

    result.x = aWidge.x * bWidge.x;

    return result;
}



int main ()
{
    Widget<int> aWidge;
    Widget<float> bWidge;
    Widget<float> cWidge;

    aWidge.SetX(2);
    bWidge.SetX(2.0);

    cWidge = aWidge*bWidge; //this should give a float return type
}
于 2014-04-15T23:32:49.877 回答