简体   繁体   中英

Defining conversion operator for specialized template class only

I want to define conversion to float for matrix<1, 1>. I have trouble figuring out how to actually define it. If I make it a global function

template<typename T>
inline operator T(const matrix<T, 1, 1> &m){ return m(0, 0); }

I get "operator.. must be a non static member function"

I can of course define it as member for the generic matrix template but then it will be defined for all matrices - which is not what I want. I want it to be defined only for the specific case of 1x1 matrix.

You have to specialize a class for that, for example:

template <typename Base, typename T, std::size_t W, std::size_t H>
struct MatrixConversion
{ /*Empty*/ };

template <typename Base, typename T> struct MatrixConversion<T, 1u, 1u>
{
    operator const T&() const { return static_cast<const Base&>(*this).m[0][0]; }
};


template <typename T, std::size_t W, std::size_t H>
struct Matrix : MatrixConversion<Matrix<T, W, H>, T, W, H>
{
    // Your code
};

composition plus specialisation would be the most maintainable approach.

You did not specify the number of dimensions in your matrix template class, so I have assumed it can be variadic.

#include <cstdint>
#include <utility>

//
// forward-declare class template for convenience.
//
template<class T, std::size_t...Dimensions>
struct matrix;

//
// classes to figure out the storage requirements of a multi-dimensional
// matrix
//
template<class T, std::size_t...Dimensions> struct storage;
template<class T, std::size_t N>
  struct storage<T, N>
  {
    using type = T[N];
  };

template<class T, std::size_t...Rest, std::size_t N>
  struct storage<T, N, Rest...>
  {
    using less_dimension_type = typename storage<T, Rest...>::type;
    using type = less_dimension_type[N];
  };


//
// functions for dereferencing multi-dimensional arrays
//
template<class Array, class Arg>
decltype(auto) deref(Array& array, Arg&& arg)
{
  return array[arg];
}

template<class Array, class Arg, class Arg2>
decltype(auto) deref(Array& array, Arg&& arg, Arg2&& arg2)
{
  return array[arg][arg2];
}

template<class Array, class Arg, class...Args>
decltype(auto) deref(Array& array, Arg&& arg, Args&&...args)
{
  return deref(deref(array, arg), std::forward<Args>(args)...);
}

//
// prototype for operations we want to conditionally apply
//
template<class Matrix>
struct matrix_conditional_ops
{
  // in the general case, none
};

//
// compose the matrix class from conditional_ops<>
//    
template<class T, std::size_t...Dimensions>
struct matrix 
  : matrix_conditional_ops<matrix<T, Dimensions...>>
{

    template<class...Dims>
    decltype(auto) at(Dims&&...ds)
    {
      return deref(_data, std::forward<Dims>(ds)...);
    }

    template<class...Dims>
    decltype(auto) at(Dims&&...ds) const
    {
      return deref(_data, std::forward<Dims>(ds)...);
    }

   typename storage<T, Dimensions...>::type _data;
};

//
// define the condition operations for the <T, 1, 1> case
//    
template<class T>
  struct matrix_conditional_ops<matrix<T, 1, 1>>
  {
    using matrix_type = matrix<T, 1, 1>;

    operator T const() { return static_cast<matrix_type const&>(*this).at(0,0); }
  };


int main()
{
  matrix<double, 1, 1> m11;

  m11.at(0,0) = 6.0;
  double d = m11;

  matrix<double, 2, 2> m22;
  // compile error:
//  double d2 = m22;

  // bonus points:

  matrix<double, 3, 5, 2, 7> mxx;
  mxx.at(2, 4, 1, 6) = 4.3;  // probably needs some compile-time checking...

}

someone may want to check my logic for the array packing/dereferencing...

Jarod and Richard already gave you the best answers in my opinion, they scale well to any number of operators with all kinds of restrictions.

However, if you cannot afford to redesign your class, or all you need is a quick and dirty opertor T() you can get away with the following

template<typename T, std::size_t N1, std::size_t N2>
struct Matrix
{
    T m[N1][N1];

    operator T()
    {
        static_assert(N1 == 1 && N2 == 1, "Only applicable to scalars");
        return m[0][0];
    }
};

Which is live here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM