簡體   English   中英

可以在模板參數中使用decltype嗎?

[英]Can you use decltype in a template parameter?

我正在嘗試重載一個乘法運算符,但不想輸入多個重載函數來考慮將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
}

仔細閱讀錯誤消息,問題很明顯:

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

應該適合此目的,並且可以說是最簡單的形式。

Visual Studio 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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM