C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::value_or

From: Eric Schmidt <eric41293_at_[hidden]>
Date: Mon, 14 Nov 2022 23:11:28 -0800
On 11/14/22 6:25 PM, Giuseppe D'Angelo via Std-Proposals wrote:
> Hi,
>
> Il 13/11/22 14:27, Roberto R via Std-Proposals ha scritto:
>> In attachment you can find a draft proposal of a function
>> std::value_or, similar to std::optional::value_or.
>>
>> In previous threads I called it coalesce.
>>
>> Can you please tell me your opinion?
>>
>
> I'm very confused by the idea that one allows both "plain values" as
> well as callables that return values to check.
>
> If I call value_or with a bunch of function pointers, trying to find the
> first non-null pointer (or return the given default), is it going to try
> to *call* these pointers because they're callables?
>
> To me, the "mere" selection facility vs. try to invoke and use the
> return values ought to be spelled _very_ differently. For instance, for
> optional there's value_or (that takes a value) and the proposed
> value_or_else that takes a callable.

I agree with this, and would add that the proposed std::value_or is
trying to do too much. There are special cases for std::function,
std::weak_ptr, and std::nullptr_t.

Rather than building lots of cases into std::value_or, I think it would
be better to have a customization point that determines whether there is
a contained value, and if so what it is.

I'm thinking along the lines of

template<class T, class U>
T value_or(T&& default_value, U&& to_test)
{
     decltype(auto) value = contained_value(std::forward<U&&>(to_test));
     return value ? *value : std::forward<T&&>(default_value);
}

when there is a single test value.

And then we can write functions like

// Generic case
// Works for optional, pointers, unique_ptr, shared_ptr
template<class T>
T&& contained_value(T&& item)
{
     return std::forward<T&&>(item);
}

// Special cases

int* contained_value(nullptr_t)
{
     return nullptr;
}

template<class T>
std::optional<T> contained_value(const std::weak_ptr<T>& item)
{
     auto p = item.lock();
     if (p)
         return *p;
     else
         return std::nullopt;
}

template<class T>
std::optional<T> contained_value(std::weak_ptr<T>& item)
{
     return contained_value(std::as_const(item));
}

(For weak_ptr, if you don't want a copy of the T, you can pass
item.lock() to value_or.)

-- 
Eric Schmidt

Received on 2022-11-15 07:11:39