On Sat, Jun 6, 2015 at 10:22 PM, Robert Ramey
I've been having a very difficult time with a problem illustrated by the following program: It looks like the eval_if in line 51 isn't working correctly. That is, the metafuction get_promotion_policy is being invoked when both types are not safe types. I've been working on this for two days and can't see what's going on. Any help from a TMP genious would be much appreciated.
#include
#include #include #include #include #include struct safe_tag {};
template
struct safe : public safe_tag { T m_t; typedef P PromotionPolicy; }; template<class T> struct is_safe : public //std::is_arithmetic<T> std::is_base_of
{}; template
struct common_policies { static_assert( boost::mpl::or_< is_safe<T>, is_safe<U> >::value, "at least one type must be a safe type" ); template<typename Z> struct get_promotion_policy { static_assert( is_safe<Z>::value, "only safe types have promotion policies" ); typedef typename Z::PromotionPolicy type; };
// if both types are safe, the policies have to be the same! static_assert( boost::mpl::eval_if< boost::mpl::and_< is_safe<T>, is_safe<U> >, typename std::is_same< typename get_promotion_policy<T>::type, typename get_promotion_policy<U>::type >::type, boost::mpl::identityboost::mpl::true_ >::type::value, "if both types are safe, the policies have to be the same!" );
// now we've verified that there is no conflict between policies // return the one from the first safe type typedef typename boost::mpl::if_< is_safe<T>, T, typename boost::mpl::if_< is_safe<U>, U, // boost::mpl::void_ >::type >::type safe_type;
typedef typename get_promotion_policy
::type promotion_policy; };
common_policies
t; int main(){ return 0; }
The problem are the immediate instantations of `typename get_promotion_policy<T>::type` which cause the static assert to be instantiated too. You need to delay instantating ::type in these objects until std::is_same needs to be evaluated. I don't know know of a way to do this with standard MPL (see https://abel.web.elte.hu/mpllibs/metamonad/lazy.html ), but one easy way with C++11 (if metaparse is not an option): template class F, typename... A> struct lazy_eval { using type = typename F<typename A::type...>::type; }; // if both types are safe, the policies have to be the same! static_assert( boost::mpl::eval_if< boost::mpl::and_< is_safe<T>, is_safe<U> >, lazy_eval< std::is_same, get_promotion_policy<T>, get_promotion_policy<U> >, boost::mpl::identityboost::mpl::true_ >::type::value, "if both types are safe, the policies have to be the same!" ); which will work with any metafunction F that accepts 1 or more arguments. There might be some way to re-write what you are trying to avoid this, but I haven't put much thought into that. Lee