[英]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.