Search code examples
c++boostboost-multiprecision

QVM - user-defined quaternion and scalar


I am trying use boost::qvm with boost::multiprecision. I built a user-defined quaternion, but I am not able to scale the quaternion. I would like to scale it by a number of type boost::multiprecision::cpp_dec_float_100. Bellow is my code. I also tried it with the out commented code.

#include <bits/stdc++.h>
#include <boost/numeric/odeint.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/qvm.hpp>

using namespace std;

typedef boost::multiprecision::cpp_dec_float_100 fl;

struct fquat { fl a[4]; };

namespace boost { namespace qvm {

  template <>
  struct quat_traits<fquat>: quat_traits_defaults<fquat,fl> {

    template <int I>
    static inline scalar_type & write_element( fquat & q ) {
      return q.a[I];
    }
  };

     template <> struct is_scalar<fl>           { static bool const value=true; };

     template <> struct scalar_traits<fl> 
     { BOOST_QVM_INLINE_CRITICAL static fl value( int v ) { return fl(v); }};
/*
     template <>
  struct deduce_quat<fquat, fl> {
    typedef fquat type;
  };

template <>
  struct deduce_quat2<fquat, fquat, fl> {
    typedef fquat type;
  };  
*/
} }




int main()
{    
    fquat q = {fl(1),fl(1),fl(1),fl(1)};
    fl x = fl(3);

    q *= x;

    return 0;
}

The error I get is:

test2.cpp: In function ‘int main()’:
test2.cpp:48:7: error: no match for ‘operator*=’ (operand types are ‘fquat’ and ‘fl’ {aka ‘boost::multiprecision::number<boost::multiprecision::backends::cpp_dec_float<100> >’})
   48 |     q *= x;
      |     ~~^~~~

Solution

  • The QVM defined operators do not get found with ADL, you need to help the compiler:

    using boost::qvm::operator*=;
    q *= x;
    

    You can make ADL work, probably in various ways.

    One way would to make boost::qvm an associated namespace for your type(s). Another would be to using the appropriate operators in your own namespace.

    Explicit Using in Your Own Namespace

    Live On Coliru

    #include <boost/multiprecision/cpp_dec_float.hpp>
    #include <boost/numeric/odeint.hpp>
    #include <boost/qvm.hpp>
    
    namespace MyLib {
        using fl = boost::multiprecision::cpp_dec_float_100;
        struct fquat {
            fl a[4];
        };
    
        using boost::qvm::operator*=;
    } // namespace MyLib
    
    namespace boost::qvm {
        template <>
        struct quat_traits<MyLib::fquat>
            : quat_traits_defaults<MyLib::fquat, MyLib::fl> {
            template <int I>
            static inline scalar_type& write_element(MyLib::fquat& q)
            {
                return q.a[I];
            }
        };
    
        template <> struct is_scalar<MyLib::fl> {
            static bool const value = true;
        };
    
        template <> struct scalar_traits<MyLib::fl> {
            BOOST_QVM_INLINE_CRITICAL static MyLib::fl value(int v)
            {
                return MyLib::fl(v);
            }
        };
    
        template <> struct deduce_quat<MyLib::fquat, MyLib::fl> {
            using type = MyLib::fquat;
        };
    
        template <> struct deduce_quat2<MyLib::fquat, MyLib::fquat, MyLib::fl> {
            using type = MyLib::fquat;
        };
    
    } // namespace boost::qvm
    
    using MyLib::fl;
    using MyLib::fquat;
    
    int main()
    {
        fquat q = {fl(1), fl(1), fl(1), fl(1)};
        fl    x = fl(3);
    
        q *= x;
    }
    

    Hack ADL

    Alternatively, using ADL-hook like e.g.

    Live On Coliru

    #include <boost/multiprecision/cpp_dec_float.hpp>
    #include <boost/numeric/odeint.hpp>
    #include <boost/qvm.hpp>
    
    namespace boost::qvm {
        struct my_ADL_hook {
        };
    } // namespace boost::qvm
    
    using fl = boost::multiprecision::cpp_dec_float_100;
    template <typename = boost::qvm::my_ADL_hook> struct fquat_t {
        fl a[4];
    };
    using fquat = fquat_t<>;
    
    namespace boost::qvm {
        template <> struct quat_traits<fquat> : quat_traits_defaults<fquat, fl> {
            template <int I> static inline scalar_type& write_element(fquat& q)
            {
                return q.a[I];
            }
        };
    
        template <> struct is_scalar<fl> {
            static bool const value = true;
        };
    
        template <> struct scalar_traits<fl> {
            BOOST_QVM_INLINE_CRITICAL static fl value(int v) { return fl(v); }
        };
    
        //template <> struct deduce_quat<fquat, fl>         { using type = fquat; } ;
        //template <> struct deduce_quat2<fquat, fquat, fl> { using type = fquat; } ;
    
    } // namespace boost::qvm
    
    int main()
    {
        fquat q = {1, 1, 1, 1};
        fl    x = 3;
    
        q *= x;
    }