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;
}
const-ness but using the value.std::forward? As others stated, the guideline is not about ruling out any code that does not meet the guideline but to help diagnose common mistakes by means of the guideline (and doing that necessarily involves false positives)