使用模板类完美转发

问题描述 投票:0回答:2

假设我有一个模板类,例如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> &&

当参数是左值时。

c++ templates rvalue-reference
2个回答
2
投票

是。从我自己的代码:

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

我不知道为什么你要它采取&&s。如果要将其他两种类型转换为矩阵然后将它们相乘,则应在乘法运算符之外进行转换。


2
投票

我也会坚持使用const引用,正如之前的回答所解释的那样。但为了澄清为什么您的代码不起作用,完美转发仅适用于对cv-unqualified模板参数使用rvalue引用时。通俗地说,它必须只是T&&,其中T是一个函数模板参数:

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

这个想法是编译器能够在传递左值时将T推导为type&(因此函数签名因参考折叠规则而变为void ForwardMe(type&)),或者只是在rvalues(签名变为type)的情况下void ForwardMe(type&&)

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

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

这不像你预期的那样工作,因为编译器不能推断T是对某事物的引用,所以你不能有完美的转发。因此,函数参数t仅匹配rvalue引用。

由于const引用可以绑定到临时对象,因此在上面的示例中使用const T<N>&将解决您的问题。但是如果你真的想同时支持左值和右值输入(因为你喜欢在适当的地方使用移动语义),你有两个选择:

  • 为所有4个排列写入重载:lvalue * lvalue,lvalue * rvalue,rvalue * lvalue,rvalue * rvalue。
  • 编写通用函数模板并使用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>

© www.soinside.com 2019 - 2024. All rights reserved.