Reputation: 303
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
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