Search code examples
templatesboostboost-mpl

boost::mpl::set thinks remove_cv<const T>::type != T


So I'm trying to get a unique list of types, and I want to get rid of all const duplicates that the list I'm passed might contain. I think the following code should work, but my_set contains "int" two times. What am i doing wrong?

#include <boost/mpl/vector.hpp>
#include <boost/mpl/transform.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/set.hpp>
#include <boost/mpl/insert.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/assert.hpp>

typedef boost::mpl::vector<float,int,float,const int>::type my_v;

typedef boost::mpl::transform
    < my_v
    , boost::remove_cv<boost::mpl::_1>::type
    >::type my_v2;

typedef boost::mpl::fold
    < my_v2
    , boost::mpl::set0<>
    , boost::mpl::insert
        < boost::mpl::_1
        , boost::mpl::_2
        >
>::type my_set;

BOOST_MPL_ASSERT_RELATION( boost::mpl::size<my_set>::value, ==, 2 ); // Fails

Solution

  • Yes as cv_and_he said, it is because of boost::remove_cv::type.

    As add ::type to boost::remove_cv will force evaluation on the expression and make remove_cv evaluate the _1 expression itself but not the underlying argument. Here transform is an recursive function, so we should remove the '::type' to allow lazy evaluation on arguments after the whole transform expression expanded.

    see the test result below,

    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/transform.hpp>
    #include <boost/type_traits/remove_cv.hpp>
    #include <boost/mpl/fold.hpp>
    #include <boost/mpl/set.hpp>
    #include <boost/mpl/insert.hpp>
    #include <boost/mpl/size.hpp>
    #include <boost/mpl/assert.hpp>
    #include <iostream>
    #include <typeinfo>
    #include <cxxabi.h>
    
    typedef boost::mpl::vector<float,int,float,const int>::type my_v;
    
    typedef boost::mpl::transform<my_v,
                                  boost::remove_cv<boost::mpl::_1>::type
                                  >::type my_v2;
    
    typedef boost::mpl::fold< my_v2,
                              boost::mpl::set0<>,
                              boost::mpl::insert<boost::mpl::_1,
                                                 boost::mpl::_2
                                                 >
                              >::type my_set;
    
    // BOOST_MPL_ASSERT_RELATION( boost::mpl::size<my_set>::value, ==, 2 ); // Fails
    
    int main()
    {
      int status;
      std::cout << abi::__cxa_demangle(typeid(boost::remove_cv<boost::mpl::_1>::type).name(), 0, 0, &status)
                << '\n'
                << abi::__cxa_demangle(typeid(boost::remove_cv<boost::mpl::_1>).name(), 0, 0, &status)
                << '\n'
                << abi::__cxa_demangle(typeid(my_v2).name(), 0, 0, &status)
                << std::endl;
    }
    

    output,

    mpl_::arg<1>
    boost::remove_cv<mpl_::arg<1> >
    boost::mpl::v_item<int const, boost::mpl::v_item<float, boost::mpl::v_item<int, boost::mpl::v_item<float, boost::mpl::vector0<mpl_::na>, 0>, 0>, 0>, 0>