Reputation: 17250
Update, thanks to AlexD's answer: This question boils down to the language rules for selecting member function overloads, which is discussed in the following question: Calling a const function rather than its non-const version
When the range expression of a range-based for loop is a call to a member function with const
and non-const
overloads, it seems that the non-const
overload is selected. As a result, the following program does not compile:
#include <iostream>
#include <vector>
class foo {
public:
const std::vector<int>& get_numbers() const { return numbers; }
protected:
std::vector<int>& get_numbers() { return numbers; }
private:
std::vector<int> numbers;
};
int main() {
foo f;
for (int x : f.get_numbers()) std::cout << x << std::endl;
}
Diagnostic message from gcc 5.3:
error: ‘std::vector<int>& foo::get_numbers()’ is protected
But a const
version of get_numbers()
is available and could be used. We can force it to be used by using a const
reference to the foo
instance, like this:
int main() {
foo f;
const foo& g = f;
for (int x : g.get_numbers()) std::cout << x << std::endl;
}
Is there a better/easier way to tell the compiler that it can and should use the const
member function overload, without explicitly making a const
reference to the object?
There are some similar questions about making the range-based for loop use const
iterators, but I haven't found any questions about making the loop's range expression const
for the purposes of selecting function overloads.
Upvotes: 0
Views: 1063
Reputation: 1871
A simple template function as_const
can make the cast not so ugly. I believe this is being added or was recently added to the standard library.
template <typename T> T const & as_const (T const & t) { return t; }
void f ()
{
for (auto && x: as_const (y)) {}
}
Upvotes: 0
Reputation: 32576
But a
const
version ofget_numbers()
is available and could be used.
The best function is selected before accessibility is considered. The standard states (emphasis mine):
If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (Clause 11) in the context in which it is used, the program is ill-formed.
Upvotes: 3