6

Is there a way to make this work with C++20?

auto view = std::views::all;

if (condition1) {
    view = view | std::views::filter([](int i) {
        return i%5 == 0;
    });
}

if (condition2) {
    view = view | std::views::filter([](int i) {
        return i%10 == 0;
    });
}

/* Do something with the view */
for (int i : list | view) {
   ...
}

I am getting this ugly error:

test.cpp:13:10: error: no match for ‘operator=’ (operand types are ‘std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >’ and ‘std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::__adaptor::operator|<std::ranges::views::<lambda(_Range&&) >::<lambda(_Up&&)> >’) 13 | }); | ^ In file included from test.cpp:2: /usr/include/c++/10/ranges:1155:14: note: candidate: ‘constexpr std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >& std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >::operator=(const std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >&)’ 1155 | struct _RangeAdaptorClosure : public _RangeAdaptor<_Callable> | ^~~~~~~~~~~~~~~~~~~~ /usr/include/c++/10/ranges:1155:14: note: no known conversion for argument 1 from ‘std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::__adaptor::operator|<std::ranges::views::<lambda(_Range&&) >::<lambda(_Up&&)> >’ to ‘const std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >&’ /usr/include/c++/10/ranges:1155:14: note: candidate: ‘constexpr std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >& std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >::operator=(std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >&&)’ /usr/include/c++/10/ranges:1155:14: note: no known conversion for argument 1 from ‘std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::__adaptor::operator|<std::ranges::views::<lambda(_Range&&) >::<lambda(_Up&&)> >’ to ‘std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::<lambda(_Range&&) >&&’ make: *** [Makefile:3: build] Error 1

I tried googling some of that RangeAdaptorClosure stuff but it's not making much sense

1 Answer 1

6

No, this is not viable code. C++ is a statically typed language, and each view you're conditionally constructing is of a different type. C++ doesn't allow you to change the type of an existing object (at least, not like that).

As such, these kinds of runtime conditional things cannot easily be done. Your case is easy enough, as you are only using filters, and you have complete control over what the filter itself is. Therefore, you could shove your conditional logic inside the filter.

But anything more complicated than that, or one not governed by filters, isn't going to work.

There are ways to do it with compile-time conditions, but these tend to get pretty ugly in terms of metaprogramming.

Sign up to request clarification or add additional context in comments.

3 Comments

Just curious - you said "each view you're conditionally constructing is of a different type"... Could there be a "general" type which encompasses both of those two types in such a way that it would allow assignment?
@matt: You could create some kind of any_filter_view that stores the functor in a std::function or equivalently type-erased construct. But such a thing doesn't exist in the standard, and you'll lose efficiency on filtering due to the indirect call.
@Nicole Ah, that makes sense. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.