Reputation: 7820
I have a simple metafunction:
template <typename T>
using is_const_lvalue_reference = mpl::and_<
std::is_lvalue_reference<T>,
std::is_const<typename std::remove_reference<T>::type>
>;
Apparently, it doesn't work if T
is an MPL placeholder because remove_reference
is evaluated for the placeholder class instead of the substituted type. How to do this correctly to be able to use this metafunction in MPL algorithms?
UPDATE: The suggested solution was to replace the alias with a struct, which will delay the template instantiation in std::remove_reference
. The question is, how to delay the instantiation inline, not using any helper structs?
template <typename Sequence>
using are_const_lvalue_references = mpl::fold<
Sequence,
mpl::true_,
mpl::and_<
mpl::_1,
mpl::and_<
std::is_lvalue_reference<mpl::_2>,
std::is_const<typename std::remove_reference<mpl::_2>::type>
>
>
>;
This example will apparently fail for the same reason. What should I change to make it correct?
Upvotes: 1
Views: 130
Reputation: 302718
It doesn't work to write type traits as aliases in this way because they get instantiated immediately. is_const_lvalue_reference<_1>
is exactly mpl::and_<std::is_lvalue_reference<_1>, std::is_const<_1>>
(since _1
isn't a reference type) - that's always false
since lvalue references aren't const
. Pretty tricky way to write false_
though!
Instead, you have to delay instantiation. Just make your type trait inherit from mpl::and_
instead of aliasing it:
template <class T>
struct is_const_lvalue_reference
: mpl::and_<
std::is_lvalue_reference<T>,
std::is_const<std::remove_reference_t<T>>
>
{ };
This way, std::remove_reference_t<T>
won't get instantiated unless we actually try to access is_const_lvalue_reference<T>::type
- which won't happen until the _1
gets substituted for the real type in apply
.
Alternatively, since apply<>
will invoke ::type
where it finds placeholders, you can just drop the explicit invocation of ::type
yourself. So this works:
BOOST_MPL_ASSERT(( mpl::apply<
std::is_const<std::remove_reference<_1>>,
int const&
> ));
or with the original expression:
BOOST_MPL_ASSERT(( mpl::apply<
mpl::and_<
std::is_lvalue_reference<_1>,
std::is_const<std::remove_reference<_1>>
>,
int const&
> ));
Note that this construction doesn't work as a type trait though.
Upvotes: 2