Question
Is Cpp Core Guidelines Rule F19 incomplete?
Cpp Core Guideline F19 tells us
Flag a function that takes a TP&& parameter (where TP is a template type parameter name) and does anything with it other than std::forwarding it exactly once on every static path.
Literally, that means something like
template<typename R, typename V> bool contains(R&& range, const V& value)
{
return std::find(range, value) != range.end();
}
Should be flagged because std::forward
was not called (and even if it was called, it'd call .end()
).
But to my understanding, this contains-implementation is correct and sensible.
I need the universal reference R&&
because in real world, I need it to bind to const&
values (1, see below) but I also need it to bind to values
that cannot become const (because begin()
and end()
aren't const) (2).
If I'd change the signature to contains(const R& range, const V& value)
, it wouldn't be compatible with most views.
int main()
{
const std::vector<int> vs{1, 2, 3, 4};
std::cout << contains(vs, 7); // (1)
std::cout << contains(vs | std::views::transform(squared), 7); // (2)
}
Question: Does F19 miss some edge case or am I missing some detail?
The std::contains
possible implementation also passes R
as a universal reference without calling std::forward
.
Alternative contains implementation using std::forward
(but also .end()
, hence not compliant with F19, either):
template<typename R, typename V> bool contains(R&& range, const V& value)
{
const auto& end = range.end();
return std::find(std::forward<R>(range), value) != end;
}