I'm overloading an operator[]
:
const Type&& operator[](int index) const {
if (index >= size) { std::cout << "Error: excessive index.\n"; return 0; }
else if (index < 0) { std::cout << "Error: negative index.\n"; return 0; }
else {
Node* temp = head->next;
for (int i = 0; i < index; i++) { temp = temp->next; }
return temp->value;
}
}
But I need a duplicate of it, which will return non-const Type value. I read that we can use perfect forwarding for cases when arguments of function can be both const or non-const (so that we wrap them in forward<Type>
every time we use it), but how to use it for value that is returned?
Also, if I simply want to return nothing, should I write return 0;
or return NULL;
? Which is more understandable?
Such unified syntax that would work for all, const
/volatile
/non-const
/lvalue/rvalue/etc., implicit object parameters is currently not supported. However, there's the proposal P0847r4: Deducing this which adds this functionality. With that, you could say:
template <typename Self>
auto&& operator[](this Self&& self, int index)
{
if (index >= self.size) { throw std::out_of_range("Error: excessive index"); }
else if (index < 0) { throw std::out_of_range("Error: negative index"); }
auto* temp = self.head;
for (int i = 0; i < index; i++) { temp = temp->next; }
return std::forward_like<Self>(temp->value);
}
Until it becomes available, the best what you can do is to shorten the implementation for const
and non-const
overloads, and delegate both calls to a static helper function template, that actually can deduce the cv-qualification and value category of the implicit object parameter:
class List
{
private:
template <typename Self>
static auto&& get(Self&& self, int index)
{
if (index >= self.size) { throw std::out_of_range("Error: excessive index"); }
else if (index < 0) { throw std::out_of_range("Error: negative index"); }
Node* temp = self.head;
for (int i = 0; i < index; i++) { temp = temp->next; }
return temp->value;
}
public:
const Type& operator[](int index) const
{
return get(*this, index);
}
Type& operator[](int index)
{
return get(*this, index);
}
private:
// ...
};
Also, note that the idiomatic approach for a function returning a reference is to throw an exception in case nothing can be returned, or to insert ad-hoc and return a new object.