Giving two template class as arguments, choose the return template class using a hierarchy order

huangapple go评论113阅读模式
英文:

Giving two template class as arguments, choose the return template class using a hierarchy order

问题

I have a class Matrix defined as template<class T, int m_rows, int m_cols = m_rows> class Matrix and an overloaded operator of the type template <class V, int m_cols2> Matrix operator * (const Matrix<V,m_cols,m_cols2>& other). The idea is that, for example, if T is complex and V is double, the returning matrix should be of the type V (complex). How do I accomplish that in the code?

As of now I have

template <class V, int m_cols2>
Matrix operator * (const Matrix<V,m_cols,m_cols2>& other) const {
    Matrix<T,m_rows,other.m_cols> res;

    for (int i = 0; i < m_rows; ++i) {
        for (int k = 0; k < other.m_rows; ++k) {
            res[i][k] = 0;
            for (int j = 0; j < m_cols; ++j) {
                res[i][k] += m_matrix[i][j]*other[j][k];
            }
        }
    }
    return res;
}

But this automatically sets the matrix "res" to the type T.
How can I tell that it should decide the type of res depending on the type hierarchy? For example
complex > double > integer?

Thanks for your answers Giving two template class as arguments, choose the return template class using a hierarchy order

I have no idea what to try Giving two template class as arguments, choose the return template class using a hierarchy order

英文:

I have a class Matrix defined as template&lt;class T, int m_rows, int m_cols = m_rows&gt; class Matrix and an overloaded operator of the type template &lt;class V, int m_cols2&gt; Matrix operator * (const Matrix&lt;V,m_cols,m_cols2&gt;&amp; other). The idea is that, for example, if T is a complex and V is a double, the returning matrix should be of the type V (complex). How do I accomplish that in the code?

As of now I have

    template &lt;class V, int m_cols2&gt;
    Matrix operator * (const Matrix&lt;V,m_cols,m_cols2&gt;&amp; other) const {
        Matrix&lt;T,m_rows,other.m_cols&gt; res;

        for (int i = 0; i &lt; m_rows; ++i) {
            for (int k = 0; k &lt; other.m_rows; ++k) {
                res[i][k] = 0;
                for (int j = 0; j &lt; m_cols; ++j) {
                    res[i][k] += m_matrix[i][j]*other[j][k];
                }
            }
        }
        return res;
    }

But this automatically sets the matrix "res" to the type T.
How can I tell that it should decide the type of res depending on the type hierarchy? For example
complex > double > integer?

Thanks for your answers Giving two template class as arguments, choose the return template class using a hierarchy order

I have no idea what to try:)

答案1

得分: 3

你可以生成一个"common type"的矩阵:

// 注意:最好不要将模板参数命名为"m_something",因为这会与类的数据成员造成混淆。
template <class OtherT, int OtherCols>
auto operator * (const Matrix<OtherT, Cols, OtherCols>& other) const
  -> Matrix<std::common_type_t<T, OtherT>, Rows, OtherCols>> // trailing return type
{
    // 使用 decltype 避免复制和粘贴返回类型。
    // 我们还可以使用推导返回类型(只是 auto,没有 trailing -> ...),
    // 但这不会对 SFINAE 友好,即:即使没有共同的类型,operator* 也会被实例化。
    decltype(*this * other) result;

    for // ...

    return result;
}

如果你的 complex 类是 std::complex,你可以像上面的示例一样使用 std::common_type。否则,你可能需要为你的类型专门化 std:common_type<Complex, ...> 以使其工作。

这是因为 double 可以隐式转换为 std::complex<double>,但反之则不行。它也适用于 intdouble,即:

static_assert(std::is_same_v<double, std::common_type_t<int, double>>); // 通过
英文:

You could produce a matrix of a "common type":

// note: it&#39;s best not to call template parameters &quot;m_something&quot;, because
//       it creates confusion with data members of the class.
template &lt;class OtherT, int OtherCols&gt;
auto operator * (const Matrix&lt;OtherT, Cols, OtherCols&gt;&amp; other) const
  -&gt; Matrix&lt;std::common_type_t&lt;T, OtherT&gt;, Rows, OtherCols&gt;&gt; // trailing return type
{
    // Avoid copying and pasing the return type with decltype.
    // We could also use a deduced return type (just auto, no trailing -&gt; ...),
    // however, this wouldn&#39;t be SFINAE-friendly, i.e.: operator* gets
    // instantiated even if there is no common type.
    decltype(*this * other) result;

    for // ...

    return result;
}

If your complex class is std::complex, you can just use std::common_type like in the above example. Otherwise you may have to specialize std:common_type&lt;Complex, ...&gt; for your type to make it work.

This works because a double is implicitly convertible to a std::complex&lt;double&gt;, but not the other way around. It also works for int and double, i.e.

static_assert(std::is_same_v&lt;double, std::common_type_t&lt;int, double&gt;&gt;); // passes

huangapple
  • 本文由 发表于 2023年6月29日 17:09:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76579639.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定