I don't understand why the following code is allowed to use the non const version of foo. I would like to forbid a const Array variable to provide a non const ArrayView.
#include <iostream>
struct ArrayView
{
ArrayView() = default;
ArrayView(const ArrayView&) = delete;
ArrayView(ArrayView&&) = delete;
void foo() {std::cout << "non const" << std::endl;}
void foo() const {std::cout << "const" << std::endl;}
};
struct Array
{
const ArrayView createView() const
{
return {};
}
};
int main()
{
const Array arr{};
auto view = arr.createView();
view.foo();
return 0;
}
output:
non const
I have gcc 10.1.0 on windows 10.
The rule of type deduction for auto
is same as template argument deduction; view
is declared as non-reference and the const
part of the return value of createView
is ignored. As the result the type of view
is ArrayView
, not const ArrayView
.
On the other hand, if you call foo
on the return value directly, the const
version would be selected. e.g.
arr.createView().foo();
As the workaround you can declare view
as const
explicitly,
const auto view = arr.createView();
Or declare view
as reference.
auto& view = arr.createView(); // the type of view is const ArrayView&
PS: I noticed that you marked both the copy/move constructor of ArrayView
as delete
. Since C++17 in auto view = arr.createView();
they'll be elided completely because of mandatory copy elision. It doesn't matter here whether they're usable or not.