eval_if fails - problem for C++ guru
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
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
On 6/6/15 8:45 PM, Lee Clagett wrote:
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.
Thanks for responding. I also believe that the problem is that is_same is getting invoked "too soon". It is for this reason I used eval_if which is intended to avoid instantiation of it's arguments but just return the type of the selected one. Clearly I've got something wrong. I tried your code exactly as you've written it but I get the same error. MPL has similar functionality in the metafunction "apply" - though I hadn't tried that. So I'm still stumped - but, again, thanks for taking the time to look at this. Robert Ramey
On Sun, Jun 7, 2015 at 11:15 AM, Robert Ramey
I also believe that the problem is that is_same is getting invoked "too soon". It is for this reason I used eval_if which is intended to avoid instantiation of it's arguments but just return the type of the selected one.
When you write `typename get_promotion_policy<T>::type`, that's an eager evaluation, not a lazy one. It doesn't matter what eval_if does, because `get_promotion_policy` has been invoked before you even get there, to compute the arguments to `eval_if`. Clearly I've got something wrong. I tried your code exactly as you've
written it but I get the same error.
Works for me with both Clang and GCC ( http://coliru.stacked-crooked.com/a/6c3d80d6839ac6e4). Tim
participants (3)
-
Lee Clagett
-
Robert Ramey
-
Tim Song