Opened 14 years ago
#1916 new Bugs
[mpl] MPL_HAS_XXX_TRAIT_DEF bug in MSVC71
Reported by: | 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 >(); }