Boost logo

Boost :

Subject: Re: [boost] [polygon] MSVC8 portability and MSVC8 bugs
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2009-07-02 14:03:36


Christian Henning wrote:
> We have to make sure we are trying to compile the same code! The
> following works when using MSVC8. There are three encompass functions.
> Can you tell me if that's the right code?
>

Remember, I didn't get any syntax error from the start when convolve() wasn't declared before the encompass() functions. When you add convolve back in the errors come back regardless of where enable_if goes. Below I have added convolve() back in and tried to use your suggestion of putting enable_if as a default argument instead of return type pattern in convolve() as well. Neither place for enable_if in convolve() is effective in eliminating the error. Still, moving convolve() to follow the three encompass() functions makes the error go away, but since they are not directly related there is no way to know why. I understand that it isn't intuitive what is going on. Your sensible approach ought to work, but we need to remember that this is a compiler bug that results in inconsistent SFINAE behavior when templates are instantiated in the context of other templates that have arguments to enable_if in common. One thing that does work is the *change the order* or arguments to gtl_and<> in the enable_if of convolve() which breaks the (compiler internal) relationship between it and the overload of encompass such that compilation is able to succeed. At this point I have enough understanding of the compiler bug to reason about how to work around it. What is required is that *no two arguments to enable_if should ever be the same between any two functions in the entire compilation unit*. This discipline can prevent the "optimization" MSVC8 is doing on template instantiations from breaking SFINAE because if no two enable_if's take the same arguments the compiler is forced to instantiate them all seperately and not change the order of instantiation (and make incorrect assumptions in doing so) in the way that breaks SFINAE. I can likely do this easily by adding extra gtl_yes parameters to the gtl_and<> logic of functions that result in the erroneous error.

By the way, what is the minimal header dependency I include to get the standard boost version of and<> to use in place of gtl_and? I found the mpl header files rather hard to navigate and the documentation didn't answer my question. Is the thing I need boost::mpl::and_<> which takes 2 or more parameters?

Thanks,
Luke

#include "isotropy.hpp"
#include "rectangle_data.hpp"
#include "point_data.hpp"
#include "point_traits.hpp"
#include "interval_traits.hpp"
#include "rectangle_traits.hpp"
#include "point_concept.hpp"
#include "interval_concept.hpp"
//#include "rectangle_concept.hpp"

namespace boost { namespace polygon {

struct rectangle_concept{};

template <typename T>
struct geometry_concept< rectangle_data< T > >
{
typedef rectangle_concept type;
};

template <typename T>
struct is_mutable_rectangle_concept { typedef gtl_no type; };
template <>
struct is_mutable_rectangle_concept< rectangle_concept > { typedef
gtl_yes type; };

template <typename T>
struct is_rectangle_concept { typedef gtl_no type; };
template <>
struct is_rectangle_concept< rectangle_concept > { typedef gtl_yes type; };

      // convolve with point
  template <typename rectangle_type, typename point_type>
 rectangle_type&
  convolve(rectangle_type& rectangle, const point_type& convolution_point,
    typename enable_if< typename gtl_and<
          typename is_mutable_rectangle_concept<typename geometry_concept<rectangle_type>::type>::type,
      typename is_point_concept<typename geometry_concept<point_type>::type>::type>::type,
                       void>::type *dummy = 0);

template< typename rectangle_type
        , typename interval_type
>
bool
encompass( rectangle_type& rectangle
         , const interval_type& b
         , orientation_2d orient
         , typename enable_if< typename gtl_and< typename
is_mutable_rectangle_concept< typename geometry_concept<
rectangle_type >::type >::type
                                               , typename
is_interval_concept < typename geometry_concept< interval_type
>::type >::type
>::type
                             , bool
>::type* ptr = 0
         )
{
    return true;
}

// enlarge rectangle to encompass the Rectangle b
template < typename rectangle_type_1
         , typename rectangle_type_2
>
bool
encompass( rectangle_type_1& rectangle
         , const rectangle_type_2& b
         , typename enable_if< typename gtl_and< typename
is_mutable_rectangle_concept<typename
geometry_concept<rectangle_type_1>::type>::type
                                               , typename
is_rectangle_concept<typename
geometry_concept<rectangle_type_2>::type>::type
>::type
                             , void
>::type* dummy = 0
      )
{
    return true;
}

// enlarge rectangle to encompass the point b
template <typename rectangle_type_1, typename point_type>
bool
encompass( rectangle_type_1& rectangle
         , const point_type& b
         , typename enable_if< typename gtl_and< typename
is_mutable_rectangle_concept< typename
geometry_concept<rectangle_type_1 >::type>::type
                                               , typename
is_point_concept < typename geometry_concept<point_type
>::type>::type
>::type
                             , void
>::type* dummy = 0
         )
{
    return true;
}

}
}

int main()
{
    using namespace boost;
    using namespace boost::polygon;
    rectangle_data<int> r;
    point_data<int> p;

    encompass(r, p);
    return 0;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk