Skip to content

Instantly share code, notes, and snippets.

@afabri
Created March 20, 2023 07:14
Show Gist options
  • Save afabri/acc723427888dc49c60099bdb6220c53 to your computer and use it in GitHub Desktop.
Save afabri/acc723427888dc49c60099bdb6220c53 to your computer and use it in GitHub Desktop.
Minimal code showing a compilation problem for boost multiprecision and operator, combined with Eigen on VC2017
#include <boost/operators.hpp>
#include <boost/multiprecision/cpp_int.hpp>
#include <Eigen/Dense>
// Quotient
template <class NT_>
class Toto
: boost::additive2 < Toto<NT_>, NT_ >
{
public:
NT_ num, den;
Toto() {}
Toto(const NT_& a) {}
Toto(const NT_& a, const NT_&b) {}
template <class T>
Toto operator+=(const T&) { return *this; }
};
// Sqrt_extension:
template <class NT_>
class Toto2
: boost::additive2 < Toto2<NT_>, NT_ >
{
public:
NT_ num, den;
Toto2() {}
Toto2(const NT_& nt)
{}
template <class T>
Toto2 operator+=(const T&) { return *this; }
};
void toto(Toto<boost::multiprecision::cpp_int>& x)
{
x.den;
}
// No idea if needed
namespace Eigen {
template<class> struct NumTraits;
template<class NT> struct NumTraits<Toto<NT> >
{
typedef Toto<NT> Real;
typedef Toto<NT> NonInteger;
typedef Toto<NT> Nested;
typedef Toto<NT> Literal;
static inline Real epsilon() { return NumTraits<NT>::epsilon(); }
static inline Real dummy_precision() { return NumTraits<NT>::dummy_precision(); }
enum {
IsInteger = 0,
IsSigned = 1,
IsComplex = 0,
RequireInitialization = NumTraits<NT>::RequireInitialization,
ReadCost = 2 * NumTraits<NT>::ReadCost,
AddCost = 150,
MulCost = 100
};
};
template<class NT> struct NumTraits<Toto2<NT> >
{
typedef Toto2<NT> Real;
typedef Toto2<NT> NonInteger;
typedef Toto2<NT> Nested;
typedef Toto2<NT> Literal;
static inline Real epsilon() { return NumTraits<NT>::epsilon(); }
static inline Real dummy_precision() { return NumTraits<NT>::dummy_precision(); }
enum {
IsInteger = 0,
IsSigned = 1,
IsComplex = 0,
RequireInitialization = NumTraits<NT>::RequireInitialization,
ReadCost = 2 * NumTraits<NT>::ReadCost,
AddCost = 150,
MulCost = 100
};
};
}
int main() {
typedef Toto2<int> NT;
Eigen::Matrix<NT, 3, 3> m(3, 3);
m + m;
return 0;
}
@afabri
Copy link
Author

afabri commented Mar 20, 2023

See also the pull request #6035

In fact in the testsuite it does not compile with VC2017. I maybe oversimplified because I just realized that this gist also does not compile with VC2022 (but with clang).

Also a hint: When I comment line 43 it compiles.

@afabri
Copy link
Author

afabri commented Mar 20, 2023

And let me share the error message. As far as I understand tries to find out if one can construct a cpp_int from a Matrix.

Build started...
1>------ Build started: Project: minimalVC2017, Configuration: Debug x64 ------
1>minimalVC2017.cpp
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(22,97): error C2039: 'value_type': is not a member of 'std::iterator_traits<void>'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(22,52): message : see declaration of 'std::iterator_traits<void>'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(32): message : see reference to class template instantiation 'boost::multiprecision::detail::is_byte_container_imp<C,true>' being compiled
1>        with
1>        [
1>            C=Eigen::Matrix<NT,3,3,0,3,3>
1>        ]
1>C:\local\boost_1_74_0\boost/type_traits/is_convertible.hpp(490): message : see reference to class template instantiation 'boost::multiprecision::detail::is_byte_container<From>' being compiled
1>        with
1>        [
1>            From=Eigen::Matrix<NT,3,3,0,3,3>
1>        ]
1>C:\local\boost_1_74_0\boost/multiprecision/cpp_int.hpp(2074,4): message : while compiling class template member function 'boost::multiprecision::backends::cpp_int_backend<0,0,boost::multiprecision::signed_magnitude,boost::multiprecision::unchecked,std::allocator<boost::multiprecision::limb_type>>::cpp_int_backend(const Container &,const boost::enable_if_c<boost::multiprecision::detail::is_byte_container<Arithmetic>::value,void>::type *)'
1>C:\GitHub\cgal\Number_types\test\Number_types\minimalVC2017.cpp(97,10): message : see reference to class template instantiation 'boost::is_convertible<Eigen::Matrix<NT,3,3,0,3,3>,Backend>' being compiled
1>        with
1>        [
1>            Backend=boost::multiprecision::backends::cpp_int_backend<0,0,boost::multiprecision::signed_magnitude,boost::multiprecision::unchecked,std::allocator<boost::multiprecision::limb_type>>
1>        ]
1>C:\local\boost_1_74_0\boost/multiprecision/number.hpp(68,4): message : while compiling class template member function 'boost::multiprecision::number<boost::multiprecision::backends::cpp_int_backend<0,0,boost::multiprecision::signed_magnitude,boost::multiprecision::unchecked,std::allocator<boost::multiprecision::limb_type>>,boost::multiprecision::et_on>::number(const V &,boost::enable_if_c<boost::is_convertible<detail::canonical<V,Backend>::type,Backend>::value&&!boost::multiprecision::detail::is_restricted_conversion<detail::canonical<V,Backend>::type,Backend>::value,void>::type *) noexcept(<expr>)'
1>        with
1>        [
1>            Backend=boost::multiprecision::backends::cpp_int_backend<0,0,boost::multiprecision::signed_magnitude,boost::multiprecision::unchecked,std::allocator<boost::multiprecision::limb_type>>
1>        ]
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(22,1): error C2146: syntax error: missing '>' before identifier 'value_type'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(22,1): error C2062: type 'unknown-type' unexpected
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(22,110): error C2039: 'type': is not a member of '`global namespace''
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(22,1): error C2238: unexpected token(s) preceding ';'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(23,142): error C2065: 'container_value_type': undeclared identifier
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(23,130): error C2923: 'boost::is_integral': 'container_value_type' is not a valid template type argument for parameter 'T'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(23,142): message : see declaration of 'container_value_type'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(23,165): error C2955: 'boost::is_integral': use of class template requires template argument list
1>C:\local\boost_1_74_0\boost/type_traits/is_integral.hpp(22,39): message : see declaration of 'boost::is_integral'
1>C:\local\boost_1_74_0\boost/multiprecision/traits/is_byte_container.hpp(23,182): error C2065: 'container_value_type': undeclared identifier
1>Done building project "minimalVC2017.vcxproj" -- FAILED.

@jzmaddock
Copy link

I'm fairly sure I remember fixing something around this area, can you please try a more up to date Boost version?

BTW I've tried to reproduce this locally, but failed so far.

@afabri
Copy link
Author

afabri commented Mar 20, 2023

With boost 1.79 it works. We would like to also support older boost versions for CGAL users.

@afabri
Copy link
Author

afabri commented Mar 21, 2023

BTW I've tried to reproduce this locally, but failed so far.

What version of boost did you use?

@jzmaddock
Copy link

I tried several going back to 1.73.

@janetournois
Copy link

I can reproduce the same errors as @afabri with Boost 1.74, Eigen 3.4 and MSVC 2017.

For consitency of our tests, here is the CMakeLists I am using

cmake_minimum_required(VERSION 3.1...3.23)
project(Number_types_Tests)

find_package(Boost 1.74 REQUIRED)
find_package(Eigen3 3.2.0 REQUIRED)

add_executable(boost-mp-operator-eigen-VC2017bug "boost-mp-operator-eigen-VC2017bug.cpp" )

target_link_libraries(boost-mp-operator-eigen-VC2017bug PUBLIC Eigen3::Eigen)
target_link_libraries(boost-mp-operator-eigen-VC2017bug PUBLIC Boost::boost)

@janetournois
Copy link

In my tests, the example does not compile with

  • Eigen 3.4 and master version
  • MSVC 2017, 2019 and 2022 compilers
  • boost 1.74

It does compile when I switch to boost 1.80

@afabri
Copy link
Author

afabri commented Mar 21, 2023

@sloriot had suggested to git bisect on boost::mp

@afabri
Copy link
Author

afabri commented Mar 22, 2023

@jzmaddock could it be a hacky fix to add a specialization of is_byte_container for Eigen::Matrix ?

typedef Eigen::Matrix<NT, 3, 3>::const_iterator It;
std::cout << typeid(It).name() << std::endl;

The output is void.

Adding this solves my problem above:

namespace boost {
    namespace multiprecision {
        namespace detail {
            template <class A, int B, int C, int D, int E, int F>
            struct is_byte_container< Eigen::Matrix<A,B,C,D,E,F>> 
            {
                static const bool value = false;
            };

} } }

In the real code I would also need a specialization for Ref<Eigen::Matrix<..>,..>, and maybe even more :<

@jzmaddock
Copy link

could it be a hacky fix to add a specialization of is_byte_container for Eigen::Matrix ?

It that fixes things, then I don't see why not - it would have to be to your code as a workaround, and you could predicate it on BOOST_VERSION should you wish - that would also protect you from any future changes to is_byte_container given that it's an implementation detail (not that I'm planning to change it, but you know, 12 months from now I'll probably have forgotten this conversation!).

@afabri
Copy link
Author

afabri commented Mar 23, 2023

I added these specializations in CGAL/config.h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment