xerion
xerion

Reputation: 303

result_of issues for both Boost and std, some compile in gcc while fail in msvc and vice versa

I wanted to ask if anyone knows why the sample code provided below does not compile in cases:
1) MSVC 2013 with boost
2) GCC with -std=c++11

The same code compiles fine
1) In MSVC when boost::result_of is swapped with the std equivalent one
2) In GCC it compiles fine when -std=c++11 flag is not enabled. In the case it is enabled using std::result_of does not help.

I am quite puzzled as to why I get such errors so I wanted to shed some light.

The classes below are as minimal as I could get it to reproduce my own, so it might not make much sense in use but it showcases the compiler error.

#include <cstdint> // or #include <boost/cstdint.hpp>
#include <vector>
//#include <type_traits> // for C11
#include <boost/type_traits.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/static_assert.hpp> // if C11 is not enabled for static assert

template <class SrcT, class DstT>
struct CopyCVR
{
    typedef typename boost::remove_reference<SrcT>::type base_src;
    typedef typename boost::remove_cv<typename boost::remove_reference<DstT>::type>::type base_dst;
    typedef typename boost::mpl::if_< boost::is_volatile<base_src>, volatile base_dst, base_dst >::type v_dst;
    typedef typename boost::mpl::if_< boost::is_const<base_src>, const v_dst, v_dst >::type cv_dst;
    typedef typename boost::mpl::if_< boost::is_reference<SrcT>, cv_dst&, cv_dst >::type type;
};

template <class typeT>
class Element2
{
    typeT elem[2];
public:
    typedef typeT elemType;

    Element2() { elem[0] = elem[1] = 0; }
    typeT& operator[](size_t i) { return elem[i]; }
};

template <class elementT>
class List
{
    std::vector<elementT> m_List;
public:
    typedef elementT list_type;
    typedef elementT& result_type;

    List() {};
    result_type operator[](size_t i) { return m_List[i]; }
    void Add(const elementT& el) { this->m_List.push_back(el); }
};

template <class ResultT, class typeT>
inline ResultT select(typeT& elem, int32_t num)
{
    return elem[num];
}

template <class List>
struct SelectFunctor
{
    int32_t m_elem;
public:
    SelectFunctor(int32_t elem) : m_elem(elem) {}

    typedef typename List::list_type::elemType listElem_type;
    typedef typename CopyCVR<typename List::result_type, listElem_type>::type result_type;

    result_type operator()(typename List::result_type elem) const
    {
        return select<result_type>(elem, m_elem);
    }
};

Here is a bit a code sample to use the above classes.

int main(int argc, _TCHAR* argv[])
{
    typedef List<Element2<double>> ListDouble;
    ListDouble list;
    SelectFunctor<ListDouble> sel(1);
    list.Add(Element2<double>());
    double val = sel(list[0]);

    #if 1 // this return a compiler error
    typedef boost::result_of< SelectFunctor<ListDouble>(typename ListDouble::list_type)>::type result_type;
    #else // this is OK
    typedef std::result_of< SelectFunctor<ListDouble>(typename ListDouble::list_type)>::type result_type;
    #endif
    static_assert(std::is_same<result_type, double&>::value, "Error");
}

In the case of MSVC+boost the compiler error is error C2039: 'type' : is not a member of 'boost::result_of (Element2)>'

In GCC I can get it to compile with boost, check sample code and compilation results over at
http://coliru.stacked-crooked.com/a/a80c29d736437eab
However if you enable C11 as in -std=c++11 and no code changes it fails. In this case as mentioned even swapping the boost::result_of with the std equivalent one does not help. Similarly compilation error log over at
http://coliru.stacked-crooked.com/a/629ee3cdb9376376

Any ideas ?

Upvotes: 2

Views: 913

Answers (1)

T.C.
T.C.

Reputation: 137404

typedef boost::result_of<SelectFunctor<ListDouble>(typename ListDouble::list_type &) >::type result_type;
//                                                                                ^

SelectFunctor's function call operator takes typename List::result_type, which is an alias for elementT&. Your result_of queries whether it is possible to call it with typename ListDouble::list_type (that typename is unnecessary, BTW), which is elementT.

The functor cannot be called with a rvalue elementT, since you can't bind a non-const lvalue reference to an rvalue. Hence, result_of has no type nested typedef in it.

Upvotes: 4

Related Questions