簡體   English   中英

模板類完美轉發

[英]Perfect forwarding with template classes

假設我有一個模板類,例如template<int n, int m> class Matrix

有沒有一種方法可以定義矩陣乘法運算符*

  1. *的參數可以是左值或右值引用
  2. *從其參數推斷出適當的返回類型(即適當的模板參數)

我的想法是

template< int n,int k, int m, template<int,int> class T1, template<int, int> class T2, template<int,int>class T3 >
 T3<n,m> operator*(T1<n,k>&&, T2<k,m>&&)//does not work

當我嘗試運行以上代碼(以明顯的方式填充主體)時,出現錯誤:

無法從Matrix <1,1>轉換為Matrix <1,1> &&

當參數是左值時。

是。 從我自己的代碼:

template
<
    int LeftColumnsRightRows, int LeftRows,
    int RightColumns
>
Matrix<RightColumns, LeftRows> operator*(Matrix<LeftColumnsRightRows, LeftRows> const& a, Matrix<RightColumns, LeftColumnsRightRows> const& b)

而且我不知道您為什么要它接受&& s。 如果要將其他兩個類型轉換為矩陣,然后將它們相乘,則應在乘法運算符之外進行轉換。

正如前面的答案所解釋的,我也將只堅持使用const引用。 但是要弄清楚為什么您的代碼不起作用,僅當您對cv-unqualified模板參數使用右值引用時,完美轉發才適用。 用外行的話來說,它必須只是T&& ,其中T是函數模板參數:

template<class T>
void ForwardMe(T&& t)
{
    DoSomething(std::forward<T>(t));
}

這個想法是,當傳遞一個左值時,編譯器將能夠推導Ttype& (因此,由於引用折疊規則,函數簽名變為void ForwardMe(type&) ),或者在出現rvalue的情況下僅type (簽名變為void ForwardMe(type&&) )。

在您的示例中,您將執行以下操作:

template<int N, template<int> class T>
void ForwardMe(T<N>&& t)
{
    // ...
}

這不符合您的預期,因為編譯器無法推斷T為對某事物的引用,因此您無法獲得完美的轉發。 因此,函數參數t將僅匹配右值引用。

由於const引用可以綁定到臨時對象,因此在上面的示例中使用const T<N>&可以解決您的問題。 但是,如果您確實想同時支持左值和右值輸入(因為您希望在適當的位置具有移動語義),則有兩種選擇:

  • 為所有4個排列寫重載:左值*左值,左值*右值,右值*左值,右值*右值。
  • 編寫通用函數模板,並使用SFINAE限制輸入類型。

后者類似於:

#include <type_traits>

template<class L, class R>
struct MatrixMulResult_helper;
template<int n, int m, int k, template<int, int> class T>
struct MatrixMulResult_helper<T<n, m>, T<m, k>> { using type = T<n, k>; };

template<class L, class R>
using MatrixMulResult = typename MatrixMulResult_helper<L, R>::type;

template<class L, class R>
MatrixMulResult<std::decay_t<L>, std::decay_t<R>>
operator*(L&& lhs, R&& rhs)
{
    // ...
}

編譯器現在可以自由推斷LR作為參考。 MatrixMulResult<>確保僅在LR (的衰減類型)分別為T<n,m>T<m,k>形式時定義此函數。 它返回一個T<n,k>

暫無
暫無

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

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