Opened 14 years ago

#1916 new Bugs

[mpl] MPL_HAS_XXX_TRAIT_DEF bug in MSVC71

Reported by: Adam Butcher <adam.butcher@…> Owned by: Aleksey Gurtovoy
Milestone: Boost 1.36.0 Component: mpl
Version: Boost 1.35.0 Severity: Problem
Keywords: mpl MPL_HAS_XXX_TRAIT_DEF msvc Cc:

Description

The MSVC71 implementation of MPL_HAS_XXX_TRAIT_DEF does not correctly support defining a trait of the same name even if that is enclosed within a different namespace. It seems to have something to do with the instantiation of the 'msvc71_sfinae_helper'. In the code below I do the following:

namespace one
{
   BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
   BOOST_MPL_HAS_XXX_TRAIT_DEF(another_type)
}

namespace two
{
   BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
}

Namespace two's has_result_type actually ends up testing for the presence of another_type rather than result_type. If the declarations in namespace one are reordered so that result_type trait is last, then the namespace two trait works as expected.

I wrote a basic sfinae trait-check implementation myself which worked ok. Maybe something similar could be used for msvc71 in the mpl?

If the following code is compiled with -DUSE_MPL_TRAIT_DEF then the mpl is used, otherwise my own implementation is used.

#if USE_MPL_TRAIT_DEF

   #define SELECTIVE_HAS_XXX_TRAIT_DEF   BOOST_MPL_HAS_XXX_TRAIT_DEF
   #include <boost/mpl/has_xxx.hpp>

#else

   #define SELECTIVE_HAS_XXX_TRAIT_DEF   MY_HAS_XXX_TRAIT_DEF
   #define MY_HAS_XXX_TRAIT_DEF( trait )                                                     \
      template <class T>                                                                     \
      struct has_##trait                                                                     \
      {                                                                                      \
         template <typename U>                                                               \
         static char test( U const volatile*, typename U::trait* = 0 );                      \
         static long test( ... );                                                            \
                                                                                             \
         static const bool value = sizeof test( static_cast<T*>(0) ) == sizeof(char);        \
      };                                                                                     \

#endif


namespace one
{
   SELECTIVE_HAS_XXX_TRAIT_DEF(result_type)
   SELECTIVE_HAS_XXX_TRAIT_DEF(another_type)
}


namespace two
{
   // This instantiation of msvc71_sfinae_helper in the msvc71
   // implementation has been seen before --- but its function is that
   // of the last trait def.
   // 
   // This line has the effect of defining a 'has_result_type' struct
   // that tests for 'another_type' in msvc71.
   //
   SELECTIVE_HAS_XXX_TRAIT_DEF(result_type)
}


template <bool> struct test;
template <> struct test<true> {};


struct X
{
   typedef int result_type;
   typedef int another_type;
};


struct Y
{
   typedef int result_type;
};


int main()
{
   test< one::has_another_type< X >::value >();
   test< one::has_result_type< X >::value >();

   // this works but is actual testing for 'another_type'!!!
   test< two::has_result_type< X >::value >();

   // this fails as it doesn't have 'another_type'
   test< two::has_result_type< Y >::value >();
}

Change History (0)

Note: See TracTickets for help on using tickets.