1

I have implemented

template<int M, int N, typename T=double>
class matrix{
    // ...
}

and would like the ability to use matrix<1,1,T> where a T is expected.

How should I accomplish this? Would the following work?

template<typename T>
operator T(matrix<1, 1, T> mat) {
    return mat(0,0);
}

(The reason for even expecting to encounter matrix<1,1,T> is that some matrix expressions have that type. For example, multiplying a matrix<1,3> by a matrix<3,1> evaluates to a matrix<1,1>.)

Museful
  • 6,711
  • 5
  • 42
  • 68

2 Answers2

3

The code you've listed will not compile, since you're essentially trying to implement a T constructor outside the definition of T; or if it's a fundamental type, or an array, it makes even less sense.

What you can do instead is implement a casting operator within your matrix class - by either adding it to the general template or specializing matrix for M=1 and N=1.

The first option would look like this:

template<int M, int N, typename T=double>
class matrix{
    // ...
    operator T() const {
        static_assert(M == 1 and N==1, 
            "Attempting to treat a matrix with multiple cells as a scalar");
        // code to return the single matrix element
    }
}

and the second:

template<int M, int N, typename T=double>
class matrix{
    // ...
}


template<typename T=double>
class matrix<1, 1, T>{
    // ... some code duplication here with the main template; or maybe
    // actually have different implementation banking on the fact that
    // it's really just a scalar.

    operator T() const {
        // code to return the single matrix element
    }
}

but frankly, I don't think I'd recommend any of these options. I'd probably do one of the following:

  • Alter function which takes a T so that it can "naturally" take 1x1 matrices (e.g. by templating)
  • Alter function which takes a T so that it can "naturally" take any matrix. A lot of scalar work has interesting generalization to matrices.
  • Be explicit about the conversion, perhaps writing a template <typename T> T as_scalar(const matrix<1,1,T> m) function.
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    There are countless functions, including many in the standard library, that take a `double` but not a `matrix<1, 1, double>`. I think this one is a good use of implicit conversion. – aschepler May 03 '18 at 23:37
  • Whenever I try to specialize templates I end up with much duplication. Would the `static_assert` approach accomplish exactly the same as template specialization, because `static_assert` counts as substitution failure in SFINAE? – Museful May 03 '18 at 23:51
  • How about `operator std::enable_if_t() const {...}`? – Museful May 06 '18 at 12:42
  • @Museful: About static_assert - I don't think that'll work, since only declartations, not definitions, are considered w.r.t. SFINAE; see [this answer](https://stackoverflow.com/a/16304778/1593077). The `enable_if_t` sounds like a good way to go. – einpoklum May 06 '18 at 14:56
0

Put this in the class definition:

template<int Md=M, int Nd=N, typename = std::enable_if_t<Md==1 && Nd==1>>
operator T() const {
    return (*this)(0,0);
}
Museful
  • 6,711
  • 5
  • 42
  • 68