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

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

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

  1. template <class V, int m_cols2>
  2. Matrix operator * (const Matrix<V,m_cols,m_cols2>& other) const {
  3. Matrix<T,m_rows,other.m_cols> res;
  4. for (int i = 0; i < m_rows; ++i) {
  5. for (int k = 0; k < other.m_rows; ++k) {
  6. res[i][k] = 0;
  7. for (int j = 0; j < m_cols; ++j) {
  8. res[i][k] += m_matrix[i][j]*other[j][k];
  9. }
  10. }
  11. }
  12. return res;
  13. }

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

  1. template &lt;class V, int m_cols2&gt;
  2. Matrix operator * (const Matrix&lt;V,m_cols,m_cols2&gt;&amp; other) const {
  3. Matrix&lt;T,m_rows,other.m_cols&gt; res;
  4. for (int i = 0; i &lt; m_rows; ++i) {
  5. for (int k = 0; k &lt; other.m_rows; ++k) {
  6. res[i][k] = 0;
  7. for (int j = 0; j &lt; m_cols; ++j) {
  8. res[i][k] += m_matrix[i][j]*other[j][k];
  9. }
  10. }
  11. }
  12. return res;
  13. }

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"的矩阵:

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

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

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

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

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

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

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.

  1. 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:

确定