19

Since ranges::view_interface has an explicit operator bool() function, this makes most C++20 ranges adaptors have the ability to convert to bool:

https://godbolt.org/z/ccbPrG51c

static_assert(views::iota(0));
static_assert("hello"sv | views::split(' '));
static_assert(views::single(0) | std::views::transform([](auto) { return 0; }));

Although this seems very convenient, do we really need this feature? The reason is that traditional STL containers such as std::vector, or commonly used views such as std::string_view, do not have this functionality of converting to bool, which seems to have some inconsistencies. And it seems more intuitive to just call .empty() or ranges::empty directly to determine whether a range is empty.

In addition, this implicit conversion maybe also causes confusion:

static_assert(!views::empty<int>);

So, why does ranges::view_interface provide this operator bool function? Are there any practical use cases?

Please note that this may be an opinion-based question, but I want to know the philosophy behind view_interface providing operator bool.

Barry
  • 286,269
  • 29
  • 621
  • 977
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • 1
    Sounds like a question for Eric Niebler. (Does Eric frequent this Q&A exchange?) – Eljay Aug 16 '21 at 17:09
  • 2
    `bool` operators are considered harmful when they are implicit. This one is `explicit` so I personally see no problem on this front. On the matter of consistency with the other containers you have a point, however imho there is no issue on adding a convenient operator that doesn't exist on containers. I would maybe have seen a problem if they would have modified the semantics of an existing operation. – bolov Aug 16 '21 at 17:09

1 Answers1

14

From this blog post by Eric Niebler, whose range-V3 library heavily influenced C++20 ranges

... custom view types can inher[i]t from view_interface to get a host of useful member functions, like .front(), .back(), .empty(), .size(), .operator[], and even an explicit conversion to bool so that view types can be used in if statements

// Boolean conversion operator comes from view_interface:
if ( auto evens = vec | view::filter(is_even) ) {
  // yup, we have some evens. Do something.
}

So this is at least one use case for converting a range view to bool. Note that this is an explicit conversion, so it only happens in a context that performs the conversion, e.g. by casting explicitly, or using it in an if condition, or in a static_assert as you have in your question.


As mentioned by Eric on a comment on this answer, this feature is not actually useful any longer for the stated use case, presumably since we now have if-with-initializers as a language construct, and so this feature could be deprecated.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • It seems to be a simplification of `if (auto evens = vec | view::filter(is_even); !evens.empty())`. – 康桓瑋 Aug 16 '21 at 21:47
  • @康桓瑋 Yes, that's true. Frankly, I don't see much use for this feature at the moment (and I haven't used it myself). It's true that the motivating case with the `if` condition is mostly reduced given if-with-initializers, but the ranges library was designed well before if-with-initializers were added to the language. – cigien Aug 16 '21 at 21:58
  • 3
    Yeah, it's not needed anymore, and could be deprecated. – Eric Niebler Aug 25 '21 at 14:13
  • Pretty much _every_ `explicit operator bool` can be spelled differently; that doesn't make them not useful. I've certainly found this one to be convenient on a number of occasions - and not having to write a negation makes it less error-prone. – T.C. Aug 25 '21 at 17:44
  • @T.C. Hmm, that's fair. Perhaps I should give it a spin, and see how it feels. The point about not needing to write a negation being less error-prone certainly makes sense. – cigien Aug 25 '21 at 21:29