3

Edit: My confusion came from not understanding the explicit specifier and contextual conversions to bool


In v19.35 you could pass an invocable to ranges::views::filter that returned std::optional. In v19.36 you cant:

https://godbolt.org/z/jcfjE3var

auto input = std::vector<std::optional<int>>{};
#if 1
// broken v19.36, works prior
    input | ranges::views::filter([](auto pair) -> std::optional<int> { return pair; });
#else 
// works
    input | ranges::views::filter([](auto pair) -> bool { return pair; });
#endif

Anyone know why?

Tom Huntington
  • 2,260
  • 10
  • 20
  • please include a [mcve] and the compiler error message in the question – 463035818_is_not_an_ai Jun 07 '23 at 10:00
  • 1
    You can add two compilers in godbolt, so you can see 19.35 accepting and 19.latest rejecting the same code side by side: https://godbolt.org/z/6ndr6TKz1 – Frodyne Jun 07 '23 at 10:08
  • When code breaks after upgrading or changing compilers, my experience tells me that it is usually because of [undefined behaviour](https://en.cppreference.com/w/cpp/language/ub) in the code that just happened to *seem to* work with the old compiler - or (rarely) it's caused by a bug in the new (or old) compiler that causes it to fail to build the code (or incorrectly accepted it previously). – Jesper Juhl Jun 07 '23 at 10:28
  • 1
    I have no idea why this is the case (thus comment, not answer). But if you change the lambda to: `return pair.second.has_value()`, then it compiles on 19.latest too. – Frodyne Jun 07 '23 at 10:47
  • @Frodyne you got my code working, so you should have given an answer. But I've changed the question now. Only God knows why `ranges::views::filter` was able to accept `T -> std::optional` in the first place – Tom Huntington Jun 07 '23 at 11:20
  • 2
    `std::optional` is contextually convertible to `bool`, due to its `operator bool()` operator. – dfrib Jun 07 '23 at 11:25
  • @TomHuntington I'm trying to find a clear definition what "predicate" is limited to for e.g. the invocable parameter for `filter`, but I can't seem to find one. Is it `T -> bool` only? – dfrib Jun 07 '23 at 11:33
  • @dfrib range-v3 has their own concept for [`std::indirect_unary_predicate`](https://en.cppreference.com/w/cpp/iterator/indirect_unary_predicate). It seems that it no longer passes this concept. I tried playing around but couldn't [get it working](https://topaz.github.io/paste/#XQAAAQARAQAAAAAAAAA6nMlWi076R8MvvqGQVBS0GR4riZfrnizPaDIPZx+7Bp4kKrvD702Z9CwNCWSiAId5Iz9SsUj9ZIWrqGp1hx7tCoUIDa3Q7+fb9t06RfJJ5WZNCulg9MNDGmJdp3C6HhWDycFTtCMS54wOf+/C0o6Ljk3CmlC3EbYMbGBNvwe/GSciK6v9cqo6ei5ddeuM4d94AP/sEh1o) – Tom Huntington Jun 07 '23 at 11:54
  • 1
    https://godbolt.org/z/sPq5cnbGK – Marek R Jun 07 '23 at 12:46

1 Answers1

1

input | ranges::views::filter([](auto pair) -> bool { return pair; }); doesn't work because std::optional<int>& is not implicitly convertible to a bool. The reason it seems to work is that you don't actually use the body of the function because you don't iterate over the view. [](std::optional<int> pair) -> bool { return pair; } shows you the error immediately.

This is also why the [](auto pair) -> std::optional<int> lambda doesn't work either: To be a valid predicate for filter, the return type needs to be boolean-testable, which requires it to be implicitly convertible to bool.

You need something like this:

    input | ranges::views::filter([](auto pair) { return bool(pair); })
Artyer
  • 31,034
  • 3
  • 47
  • 75
  • 1
    @TomHuntington The godbolt link you've given shows it not working, I don't think that ever worked. It is just ill formed because there is no implicit conversion from optional to bool. Also I found out why previous versions accepted optional-producing functors: ranges-v3 library's `ranges::predicate` was broken https://godbolt.org/z/7qcs9Yrx3 – Artyer Jun 07 '23 at 23:04
  • So I'm realizing that `[](std::optional o) -> bool { return o; }` never used to work. Still I'm not sure why `[](std::optional o) -> std::optional { return o; }` used to work – Tom Huntington Jun 07 '23 at 23:06
  • "ranges-v3 library's ranges::predicate was broken" thanks – Tom Huntington Jun 07 '23 at 23:08
  • I now understand the `explicit` specifier and contextual conversions to bool. https://en.cppreference.com/w/cpp/language/implicit_conversion#Contextual_conversions O c++ why do you do this to me. – Tom Huntington Jun 07 '23 at 23:41