Is this some kind of pattern?
auto [ value, status ] = valstat_enabled_function () ;
if ( value && status ) { /* info */ }
if ( value && ! status ) { /* ok */ }
if ( ! value && status ) { /* error*/ }
if ( ! value && ! status ) { /* empty*/ }
or you just check all possibilities?
I believe more often one use it as following:
auto [ fd, status ] = modern_fopen("/tmp/abc");
switch(status){
case FStatus::NOT_FOUND: return display_error("File not found");
case FStatus::INCORRECT: return display_error("incorrect");
case OK: /* ok */
}
// use file descriptor
close(fd);
I am unsure why I should use "std" valstat and not make my own with say std::pair or custom struct? - show intention? (this is a very good reason)
about implementation, I would never do status std::optional.
is debatable if value should be std::optional too.
If you see the example with file descriptor - it is int - if status is incorrect, we can put anything there (not just -1) and it will have a small memory footprint and perform faster than std::optional.
Same with iterators - they are usually pointers or structs with a pointer or two inside.:
class SkipList::iterator{
public:
constexpr iterator(const Node *node) : node_(node){}
public:
using difference_type = SkipList::difference_type;
using value_type = const Pair;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
public:
iterator &operator++();
reference operator*() const;
public:
bool operator==(const iterator &other) const{
return node_ == other.node_;
}
bool operator!=(const iterator &other) const{
return ! operator==(other);
}
pointer operator ->() const{
return & operator*();
}
private:
const Node *node_;
};
If one needs std::optional, he / she can add it.
So implementation should be more like that:
namespace std {
template< typename T, typename S>
struct [[nodiscard]] valstat{
using value_type = T;
using status_type = S;
T value;
S status;
};
template< typename T, typename S>
auto make_valstat(T t, S s){
// to do - fix forward mess :)
valstat<T,S>(t, s);
}
} // std
I also would make function similar to std::make_pair - even you can use CTAD, make_pair still show intend;
Regards