Перегрузить operator[] для встроенных типов, от своих типов
Я пытаюсь добавить немного типобезопасности и создаю тип:
struct Number
{
explicit Number(int v) : value(v) {}
explicit operator int() { return value; }
// ... //
private:
int value;
};
Затем, я хочу добавить возможность доступа к элементу массива по его "номеру" Number:
template <class T>
T& operator[](T* arr, Number i) { return arr[(int)i]; }
Однако определять operator[] вне типа запрещено стандартом.
Есть ли обходной путь сделать данный оператор, кроме определения собственного типа массива?
Ответы (3 шт):
типы для индексации зашиты там намертво, думаю можно писать только свои велосипеды.
возможные варианты решения по моему мнению:
- наследоваться от нужного контейнера и расширить функционал(плохая идея, так как контейнеры стандартной библиотеки не имеют виртуальных деструкторов)
- писать свой контейнер с нужным функционалом
- скопировать реализацию нужного контейнера и изменить в нем необходимые методы(рассматривайте это как шуточный вариант, так как этот вариант не сочетается ни с какими идиомами)
- композиция, поместить вектор в какой нибудь класс, и сделать свой интерфейс, вызывая методы
vector
небольшой пример для (1) случая, наследуемся от vector и добавляем operator[] принимающий Number в качестве индекса
#include <iostream>
#include <vector>
struct Number
{
explicit Number(const int v) : value(v) {}
explicit operator int() const { return value; }
// ... //
private:
int value;
};
template <typename T>
class ExtendedVector : public std::vector<T>
{
public:
_NODISCARD T& operator[](const Number& pos) noexcept
{
return std::vector<T>::operator[](int(pos));
}
_NODISCARD const T& operator[](const Number& pos) const noexcept
{
return std::vector<T>::operator[](int(pos));
}
};
int main()
{
ExtendedVector<int> values;
values.push_back(3);
values.push_back(2);
values.push_back(4);
std::cout << values[Number(0)] << '\n';
std::cout << values[Number(1)] << '\n';
std::cout << values[Number(2)] << '\n';
return 0;
}
как по мне это очень грустно выглядит и нужно определить кучу конструкторов, которые будут отправлять аргументы в конструкторы родителя-vector и еще кучу всего чтобы этот контейнер хотя бы работал как vector
Можно просто убрать explicit у оператора преобразования:
#include <iostream>
struct Number {
explicit Number(int v) : value(v) {}
operator int() { return value; }
// ... //
private:
int value;
};
int main() {
int arr[] = {1, 2, 3};
std::cout << arr[Number(1)] << '\n';
}
Или оставить explicit operator int, но сделать оператор преобразования для std::size_t без explicit.
Можно подойти с другой стороны: добавить к Number шаблонный метод th_element_of с семантикой "N-й элемент контейнера"
class Number
{
template <typename Item>
Item& th_element_of(Item* items)
{
return items[value];
}
};
SomeType items[];
//...
Number n = ....
auto item = n.th_element_of(items);
название метода подобрать по вкусу