einpoklum
einpoklum

Reputation: 131636

any_cast with std::any's and std::optional

If I put a T into an std::any, I can get it with any_cast<T>(my_any). But does the standard (= C++17, in the ballot phase at the moment) include a function like any_cast<T>(optional<any> oa) which returns nullopt if oa is nullopt and std::any_cast<T>(oa.value()) otherwise? Or something along those lines?

Edit: Since people seem to be suggesting implementations, I'll also list what I use for now:

/* using magic here to select between boost/std::experimental/std versions */

template<typename T>
inline const optional<T> any_cast(const optional<any>& operand)
{
    return operand ? 
        optional<T>(any_cast<T>(operand.value())) :
        optional<T>(nullopt);
}

Upvotes: 3

Views: 1396

Answers (2)

Barry
Barry

Reputation: 303107

If std::optional had a bind (or and_then) member function (that is, a function on optional<T> which takes a T -> optional<U> and either invokes it or returns nullopt), then that's what you'd be looking for:

std::optional<std::any>> oa;

optional<T> opt_t = oa.bind([](std::any& v) -> std::optional<T> {
    if (T* t = std::any_cast<T>(&v)) {
        return *t;
    }
    else {
        return std::nullopt;
    }
});

or, if you really want to directly invoke any_cast<T> and deal with throwing, map:

optional<T> opt_t = oa.map([](std::any& v) {
    return std::any_cast<T>(v);
});

std::optional has no continuation functions though, so you'd have to write those as non-member functions.

Upvotes: 0

Vittorio Romeo
Vittorio Romeo

Reputation: 93294

There is no mention of anything like that in the std::optional proposal or in the std::any proposal.

I suppose it would be trivial to implement using a continuation function, since the return type is different depending on the state of the optional object:

template <typename T, typename TOptional, typename TF>
void any_cast_or_nullopt(TOptional&& o, TF&& f)
{
    if(!o) return; 
    f(std::any_cast<T>(*o));
}

Add static_assert and/or SFINAE where appropriate to constrain the function. The value *o should also be forwarded depending on o's value category. Example usage:

int out = -1;

std::optional<std::any> x;
x = 10;

any_cast_or_nullopt<int>(x, [&out](int value)
    {
        out = value;
    });

assert(out == 10);

Upvotes: 1

Related Questions