1

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?

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks, it works this way, but if I ditch the struct and just use the expression in-place (inside a bigger MPL expression), I still get the same problem. How should I deal with that?
@lizarisk I don't know what that means. Perhaps ask a new question with specifics?
I mean, I understood that transforming an alias to a struct delays the template instantiation and solves the problem, but what if I just want use the expression inline (i.e. remove_reference in this case)? How should I delay template instantiation?
@lizarisk Updated.
Thanks! I dropped this solution because I was trying to use this both as type traits and as a part of a placeholder expression, and that got me confused for some reason.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.