c++boost

Boost integer_modulus Usage


Boost documentation mentions the integer_modulus function.

template <class Integer1, class Integer2>
Integer2 integer_modulus(const Integer1& x, Integer2 val);

I've found that it resides in boost/multiprecision/integer.hpp in the boost::multiprecision namespace. However, I cannot figure out how to make it work. I tried different compilers but got the same no matching and possible candidates errors at the compilation stage. The example is here.

#include <iostream>
#include <boost/multiprecision/integer.hpp>
#include <boost/multiprecision/cpp_int.hpp>

namespace mp = boost::multiprecision;
using bigint_t = mp::int256_t;

int main() {
  bigint_t a = -28;
  bigint_t b = 10;
  bigint_t c = mp::integer_modulus(a, b);
  std::cout << (a % b) << std::endl;
  std::cout << c << std::endl;

  return 0;
}

Errors:

<source>: In function 'int main()':
<source>:11:35: error: no matching function for call to 'integer_modulus(bigint_t&, bigint_t&)'
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
In file included from /opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/cpp_int.hpp:20,
                 from /opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:11,
                 from <source>:2:
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:155:1: note: candidate: 'template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Integer> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<I>::value && (boost::multiprecision::number_category<Num>::value == boost::multiprecision::number_kind_integer)), Integer>::type boost::multiprecision::integer_modulus(const number<Backend, ExpressionTemplates>&, Integer)'
  155 | integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
      | ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:155:1: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp: In substitution of 'template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Integer> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<I>::value && (boost::multiprecision::number_category<Num>::value == boost::multiprecision::number_kind_integer)), Integer>::type boost::multiprecision::integer_modulus(const number<Backend, ExpressionTemplates>&, Integer) [with Backend = boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>; boost::multiprecision::expression_template_option ExpressionTemplates = boost::multiprecision::et_off; Integer = boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >]':
<source>:11:35:   required from here
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:155:1: error: no type named 'type' in 'struct std::enable_if<false, boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> > >'
  155 | integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
      | ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:163:1: note: candidate: 'template<class tag, class A1, class A2, class A3, class A4, class Integer> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<I>::value && (boost::multiprecision::number_category<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == boost::multiprecision::number_kind_integer)), Integer>::type boost::multiprecision::integer_modulus(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>&, Integer)'
  163 | integer_modulus(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, Integer val)
      | ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:163:1: note:   template argument deduction/substitution failed:
<source>:11:35: note:   'bigint_t' {aka 'boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >'} is not derived from 'const boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>'
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:46:179: note: candidate: 'template<class I1, class I2> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<T>::value && boost::multiprecision::detail::is_integral<Arithmetic>::value), I2>::type boost::multiprecision::integer_modulus(const I1&, I2)'
   46 | inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
      |                                                                                                                                                                                   ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:46:179: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp: In substitution of 'template<class I1, class I2> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<T>::value && boost::multiprecision::detail::is_integral<Arithmetic>::value), I2>::type boost::multiprecision::integer_modulus(const I1&, I2) [with I1 = boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >; I2 = boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >]':
<source>:11:35:   required from here
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:46:179: error: no type named 'type' in 'struct std::enable_if<false, boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> > >'
   46 | inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
      |                                                                                                                                                                                   ^~~~~~~~~~~~~~~
ASM generation compiler returned: 1
<source>: In function 'int main()':
<source>:11:35: error: no matching function for call to 'integer_modulus(bigint_t&, bigint_t&)'
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
In file included from /opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/cpp_int.hpp:20,
                 from /opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:11,
                 from <source>:2:
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:155:1: note: candidate: 'template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Integer> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<I>::value && (boost::multiprecision::number_category<Num>::value == boost::multiprecision::number_kind_integer)), Integer>::type boost::multiprecision::integer_modulus(const number<Backend, ExpressionTemplates>&, Integer)'
  155 | integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
      | ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:155:1: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp: In substitution of 'template<class Backend, boost::multiprecision::expression_template_option ExpressionTemplates, class Integer> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<I>::value && (boost::multiprecision::number_category<Num>::value == boost::multiprecision::number_kind_integer)), Integer>::type boost::multiprecision::integer_modulus(const number<Backend, ExpressionTemplates>&, Integer) [with Backend = boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>; boost::multiprecision::expression_template_option ExpressionTemplates = boost::multiprecision::et_off; Integer = boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >]':
<source>:11:35:   required from here
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:155:1: error: no type named 'type' in 'struct std::enable_if<false, boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> > >'
  155 | integer_modulus(const number<Backend, ExpressionTemplates>& x, Integer val)
      | ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:163:1: note: candidate: 'template<class tag, class A1, class A2, class A3, class A4, class Integer> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<I>::value && (boost::multiprecision::number_category<typename boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>::result_type>::value == boost::multiprecision::number_kind_integer)), Integer>::type boost::multiprecision::integer_modulus(const detail::expression<tag, Arg1, Arg2, Arg3, Arg4>&, Integer)'
  163 | integer_modulus(const multiprecision::detail::expression<tag, A1, A2, A3, A4>& x, Integer val)
      | ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/detail/integer_ops.hpp:163:1: note:   template argument deduction/substitution failed:
<source>:11:35: note:   'bigint_t' {aka 'boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >'} is not derived from 'const boost::multiprecision::detail::expression<tag, Arg1, Arg2, Arg3, Arg4>'
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:46:179: note: candidate: 'template<class I1, class I2> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<T>::value && boost::multiprecision::detail::is_integral<Arithmetic>::value), I2>::type boost::multiprecision::integer_modulus(const I1&, I2)'
   46 | inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
      |                                                                                                                                                                                   ^~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:46:179: note:   template argument deduction/substitution failed:
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp: In substitution of 'template<class I1, class I2> constexpr typename std::enable_if<(boost::multiprecision::detail::is_integral<T>::value && boost::multiprecision::detail::is_integral<Arithmetic>::value), I2>::type boost::multiprecision::integer_modulus(const I1&, I2) [with I1 = boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >; I2 = boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> >]':
<source>:11:35:   required from here
   11 |   bigint_t c = mp::integer_modulus(a, b);
      |                ~~~~~~~~~~~~~~~~~~~^~~~~~
/opt/compiler-explorer/libs/boost_1_85_0/boost/multiprecision/integer.hpp:46:179: error: no type named 'type' in 'struct std::enable_if<false, boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void> > >'
   46 | inline BOOST_MP_CXX14_CONSTEXPR typename std::enable_if<boost::multiprecision::detail::is_integral<I1>::value && boost::multiprecision::detail::is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
      |                                                                                                                                                                                   ^~~~~~~~~~~~~~~
Execution build compiler returned: 1

So, the question is: How to make it work?


Solution

  • You missed a key point in the documentation. In your link the key point is that the functions

    are overloaded for the fundamental (built-in) integer types

    And indeed if you look at the source code the function is defined as

    template <class I1, class I2>
    typename enable_if_c<is_integral<I1>::value && is_integral<I2>::value, I2>::type integer_modulus(const I1& x, I2 val)
    {
       return static_cast<I2>(x % val);
    }
    

    And as you can see it is constrained to types where is_integral<Type> is true.