mpl::if_ or mpl::apply_if?
Hi!
I am trying to migrate some parts of my code from
loki to boost::mpl.
Q1: which is the best way to perform nested if-then-else?
Assume given "values":
bool B1, bool B2;
class ff, class tf, class ft, class tt;
I replaced
-----------------------------------------------------------
typedef typename
Loki::Select
,
apply_if < bool_c<B2>, identity<ft>, identity<ff>
::type type;
Q2: Is apply_if always to be preferred over if_? Q3: (OT) Is there a mpl-equivalent to run-time case? best regards, Markus
From: "Markus Werle"
I am trying to migrate some parts of my code from loki to boost::mpl.
Q1: which is the best way to perform nested if-then-else?
Assume given "values": bool B1, bool B2; class ff, class tf, class ft, class tt;
I replaced
----------------------------------------------------------- typedef typename Loki::Select
::Result, typename Loki::Select ::Result >::Result type; ----------------------------------------------------------- with
typedef typename apply_if < bool_c<B1>,
apply_if < bool_c<B2>, identity<tt>, identity<tf>
,
apply_if < bool_c<B2>, identity<ft>, identity<ff>
::type type;
Q2: Is apply_if always to be preferred over if_?
mpl::if_ is the same as Loki::Select (actually, mpl::if_c is). mpl::apply_if
does a "::type" on the result. Thus, the following two are equivalent:
mpl::if_<...>::type::type
mpl::apply_if<...>::type
This is useful for delaying evaluation. For example:
// Add reference if "flag" is true
typedef mpl::if_c ::type new_type; If T is void, the above will give an error (reference to void), even if
"flag" is false. This is because "add_reference<T>::type" instantiates the
template, regardless of the outcome of the if_c. However, if you instead do
it like this:
typedef mpl::if_c ::type::type new_type; then there won't be a problem, because add_reference<T> doesn't get
instantiated in this case. The above may be written as:
typedef mpl::apply_if_c ::type new_type; Thus, this is an important idiom: Preventing eager evaluation of the
arguments. apply_if just gives a handy way of doing it. If you don't need
this, then if_ can be used just as well. Q3: (OT) Is there a mpl-equivalent to run-time case? I don't think so. That could be a good addition.
Regards,
Terje
Markus Werle
Hi!
I am trying to migrate some parts of my code from loki to boost::mpl.
Q1: which is the best way to perform nested if-then-else?
Assume given "values": bool B1, bool B2; class ff, class tf, class ft, class tt;
I replaced
----------------------------------------------------------- typedef typename Loki::Select
::Result, typename Loki::Select ::Result >::Result type; ----------------------------------------------------------- with
typedef typename apply_if < bool_c<B1>,
apply_if < bool_c<B2>, identity<tt>, identity<tf>
,
apply_if < bool_c<B2>, identity<ft>, identity<ff>
::type type;
typedef typename
mpl::apply_if_c<
B1
, mpl::if_c
Q2: Is apply_if always to be preferred over if_?
No
apply_if
Q3: (OT) Is there a mpl-equivalent to run-time case?
:-) Aleksey and I have been discussing some shorthands for if (c1) then t1 else if (c2) then t2 else if (c3) then t3 ... else if (c4) then t4 but that's not quite the same as a case statement. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
Markus Werle
writes:
Q3: (OT) Is there a mpl-equivalent to run-time case?
:-)
Aleksey and I have been discussing some shorthands for
if (c1) then t1 else if (c2) then t2 else if (c3) then t3 ... else if (c4) then t4
but that's not quite the same as a case statement.
A std::map equivalent would help here a lot.
It should be possible to search within a typelist of
std::pair
Markus Werle wrote:
Q3: (OT) Is there a mpl-equivalent to run-time case?
:-)
Aleksey and I have been discussing some shorthands for
if (c1) then t1 else if (c2) then t2 else if (c3) then t3 ... else if (c4) then t4
but that's not quite the same as a case statement.
A std::map equivalent would help here a lot. It should be possible to search within a typelist of std::pair
... Unfortunately I am still stumbling through the mpl source [getting mad about all those WORKAROUND_FOR(STUPID_COMPILER_VENDOR)] Could You please give me an idea how to search within such a typelist?
With the current CVS, you don't have to do it by yourself:
#include "boost/mpl/vector.hpp"
#include "boost/mpl/switch.hpp"
#include "boost/mpl/project1st.hpp"
#include "boost/mpl/pair.hpp"
#include "boost/mpl/always.hpp"
#include "boost/mpl/bool_c.hpp"
#include "boost/mpl/assert_is_same.hpp"
#include "boost/type_traits/remove_reference.hpp"
#include "boost/type_traits/add_const.hpp"
#include "boost/type_traits/is_pointer.hpp"
#include "boost/type_traits/is_reference.hpp"
using namespace boost::mpl;
typedef vector<
pair< boost::is_pointer<_1>, _1 >
, pair< boost::is_reference<_1>, boost::remove_reference<_1> >
, pair< always
From: "Aleksey Gurtovoy"
Markus Werle wrote:
Q3: (OT) Is there a mpl-equivalent to run-time case?
With the current CVS, you don't have to do it by yourself:
#include "boost/mpl/switch.hpp"
Ah, so you _have_ implemented switch. :) I checked the CVS and I see that it was committed _today_. :) Did you implement it at the response of the posting here? I mentioned in my reply in this thread that it could be a good addition (before it had been added to the CVS), and that was fast done. :) Regards, Terje
Terje Slettebø wrote:
With the current CVS, you don't have to do it by yourself:
#include "boost/mpl/switch.hpp"
Ah, so you _have_ implemented switch. :) I checked the CVS and I see that it was committed _today_. :) Did you implement it at the response of the posting here?
Almost; David and I were discussing something like this on and off for a long time, so I have quite a number of different variations of it laying around. I just finally chose one and checked it in in response to Markus' query :). Aleksey
Terje Slettebø
From: "Aleksey Gurtovoy"
Markus Werle wrote:
Q3: (OT) Is there a mpl-equivalent to run-time case?
With the current CVS, you don't have to do it by yourself:
#include "boost/mpl/switch.hpp"
Ah, so you _have_ implemented switch. :) I checked the CVS and I see that it was committed _today_. :) Did you implement it at the response of the posting here?
We've been discussing that for a long time, so I think Aleksey had the implementation in his head for a while.
I mentioned in my reply in this thread that it could be a good addition (before it had been added to the CVS), and that was fast done. :)
I think it would've happened sooner if I'd been more thrilled with the syntax ;-) -- Dave Abrahams Boost Consulting www.boost-consulting.com
Aleksey Gurtovoy wrote:
With the current CVS, you don't have to do it by yourself:
#include "boost/mpl/vector.hpp" #include "boost/mpl/switch.hpp" #include "boost/mpl/project1st.hpp" #include "boost/mpl/pair.hpp" #include "boost/mpl/always.hpp" #include "boost/mpl/bool_c.hpp" #include "boost/mpl/assert_is_same.hpp"
#include "boost/type_traits/remove_reference.hpp" #include "boost/type_traits/add_const.hpp" #include "boost/type_traits/is_pointer.hpp" #include "boost/type_traits/is_reference.hpp"
using namespace boost::mpl;
typedef vector< pair< boost::is_pointer<_1>, _1 > , pair< boost::is_reference<_1>, boost::remove_reference<_1> > , pair< always
, boost::add_const<_1> > > switch_body; typedef switch_< switch_body, char& >::type t1; typedef switch_< switch_body, int* >::type t2; typedef switch_< switch_body, int >::type t3;
BOOST_MPL_ASSERT_IS_SAME(t1, char); BOOST_MPL_ASSERT_IS_SAME(t2, int*); BOOST_MPL_ASSERT_IS_SAME(t3, int const);
Does it cover your needs?
It covers my needs and it makes me feel like a stupid KnowNothing (after 5 years in expression template metaprogramming) What are the requirements for the struct some_condition<_1> to be used in such a switch body? Markus
Markus Werle wrote:
using namespace boost::mpl;
typedef vector< pair< boost::is_pointer<_1>, _1 > , pair< boost::is_reference<_1>, boost::remove_reference<_1> > , pair< always
, boost::add_const<_1> > > switch_body; typedef switch_< switch_body, char& >::type t1; typedef switch_< switch_body, int* >::type t2; typedef switch_< switch_body, int >::type t3;
BOOST_MPL_ASSERT_IS_SAME(t1, char); BOOST_MPL_ASSERT_IS_SAME(t2, int*); BOOST_MPL_ASSERT_IS_SAME(t3, int const);
[...]
What are the requirements for the struct some_condition<_1> to be used in such a switch body?
'some_condition' should be a metafunction
(http://www.mywikinet.com/mpl/ref/Metafunction.html) "returning" a bool
Integral Constant (http://www.mywikinet.com/mpl/ref/Integral_Constant.html),
e.g.
using namespace boost::mpl;
template< typename T > struct silly
{
typedef bool_<(sizeof(T) > 50)> type;
};
typedef vector<
pair< silly<_1>, always<void> >
, pair< always
Markus Werle
Aleksey Gurtovoy wrote:
With the current CVS, you don't have to do it by yourself:
#include "boost/mpl/vector.hpp" #include "boost/mpl/switch.hpp" #include "boost/mpl/project1st.hpp" #include "boost/mpl/pair.hpp" #include "boost/mpl/always.hpp" #include "boost/mpl/bool_c.hpp" #include "boost/mpl/assert_is_same.hpp"
#include "boost/type_traits/remove_reference.hpp" #include "boost/type_traits/add_const.hpp" #include "boost/type_traits/is_pointer.hpp" #include "boost/type_traits/is_reference.hpp"
using namespace boost::mpl;
typedef vector< pair< boost::is_pointer<_1>, _1 > , pair< boost::is_reference<_1>, boost::remove_reference<_1> > , pair< always
, boost::add_const<_1> > > switch_body; typedef switch_< switch_body, char& >::type t1; typedef switch_< switch_body, int* >::type t2; typedef switch_< switch_body, int >::type t3;
BOOST_MPL_ASSERT_IS_SAME(t1, char); BOOST_MPL_ASSERT_IS_SAME(t2, int*); BOOST_MPL_ASSERT_IS_SAME(t3, int const);
Does it cover your needs?
It covers my needs and it makes me feel like a stupid KnowNothing (after 5 years in expression template metaprogramming)
What are the requirements for the struct some_condition<_1> to be used in such a switch body?
It should be a unary lambda expression or metafunction class returning an integral constant wrapper. It is evaluated on the 2nd switch argument to determine whether that case is selected. The definition of a lambda expression is: A lambda expression is a placeholder or a template with at least one argument that is a lambda expression. For now, "always<X>" is also a lambda expression. A metafunction class is a class with a nested metafunction named "apply" HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (4)
-
Aleksey Gurtovoy
-
David Abrahams
-
Markus Werle
-
Terje Slettebø