Перегрузка оператора индекса класса для доступа к элементам объекта std :: vector

Я анализирую текстовый файл для чтения переменных из него. Наличие переменных в файле важно, поэтому я решил написать шаблонный класс, который будет содержать оба значения переменной (Value) и флаг его существования (Exists).

template<class Type>
class MyVariable
{
public:
Type    Value;
bool    Exists;
MyVariable()
: Exists(false), Value(Type())
{
}
MyVariable(const Type & Value)
: Exists(true), Value(Value)
{
}
MyVariable(const Type && Value)
: Exists(true), Value(std::move(Value))
{
}
MyVariable(const Type & Value, bool Existance)
: Exists(Existance), Value(Value)
{
}
MyVariable(const Type && Value, bool Existance)
: Exists(Existance), Value(std::move(Value))
{
}
size_t size() const
{
return Value.size();
}
const MyVariable & operator=(const MyVariable &  Another)
{
Value   = Another.Value;
Exists  = true;
}
const MyVariable & operator=(const MyVariable && Another)
{
Value   = std::move(Another.Value);
Exists  = true;
}
const Type & operator[](size_t Index) const
{
return Value[Index];
}
Type & operator[](size_t Index)
{
return Value[Index];
}
operator const Type & () const
{
Value;
}
operator Type &()
{
Value;
}
};

Тип хранимой переменной будет иногда std::vector, так что я перегружен подстрочный оператор operator[] для прямого доступа к элементам вектора. Так что я могу сделать Value а также Exists Члены частные.

Я использую этот класс, как это в коде:

const MyVariable<std::vector<int>> AVector({11, 22, 33, 44 ,55});
for (size_t i=0; i<AVector.size(); i++)
{
std::wcout << L"Vector element #" << i << L" --> " << AVector.Value[i]  << std::endl;   // Works okay.
std::wcout << L"Vector element #" << i << L" --> " << AVector[i]        << std::endl;   // Gives error.
}

Я получаю следующее сообщение об ошибке:

Ошибка C2679 бинарная '<<': оператор не найден, который принимает правый операнд типа 'const std::vector<int,std::allocator<_Ty>>' (или нет приемлемого преобразования)

Что я здесь не так делаю?

2

Решение

const Type & operator[](size_t Index) const
{
return Value[Index];
}

Type & operator[](size_t Index)
{
return Value[Index];
}

Эти возвращаемые типы неверны; вы возвращаете содержащийся тип, а не тип контейнера. Ты можешь использовать decltype за это:

auto operator[](size_t Index) const -> decltype(Value[Index])
{
return Value[Index];
}

auto operator[](size_t Index) -> decltype(Value[Index])
{
return Value[Index];
}
4

Другие решения

Вы возвращаете неправильный тип.

За const Type & operator[](size_t Index) const, Type является std::vector<int>Это означает, что вы пытаетесь вернуть vector, а не элемент vector,

Попробуйте изменить тип возвращаемого значения на typename Type::value_type, такие как

const typename Type::value_type& operator[](size_t Index) const
3

Перегрузка вашего оператора объявлена

const Type & operator[](size_t Index) const

Но AVector объявлен как

const MyVariable<std::vector<int>>

Так Type в вашем случае это std :: vector, а нет << перегрузка оператора, которая принимает std :: vector для cout.

2

TartanLlama-х а также songyuanyao-х ответы верны только тогда, когда содержится переменная типа (т. е .; ValueType) является std::vector, Если мы попытаемся сохранить фундаментальный тип данных (например, int или же float), компилятор (MSVC14) выдает ошибку ниже, поскольку не будет никакого неявного оператора индекса operator[] или же value_type определение типа члена внутри.

'InputFileVariable<bool,std::string>::value_type': is not a type name, static, or enumerator
'InputFileVariable<int,std::string>::value_type': is not a type name, static, or enumerator
'InputFileVariable<uintmax_t,std::string>::value_type': is not a type name, static, or enumerator
'InputFileVariable<float,std::string>::value_type': is not a type name, static, or enumerator

Я нашел решение с помощью шаблонов функций. Я переписал операторы индекса как шаблоны, чтобы компилятор не создавал функции-члены индекса, если они не были вызваны. И так как я называю их только тогда, когда хранимый элемент является std::vector, это не вызывает никаких проблем с фундаментальными типами.

Мой рабочий окончательный код ниже.

#include <vector>
#include <string>

template<class ValueType, class KeyType = std::string>
class InputFileVariable
{
public:
const KeyType   Key;
ValueType       Value;
bool            Exists;
InputFileVariable(KeyType && Key, ValueType && Value, bool Existance = false)
:   Key     (std::forward<KeyType>  (Key)),
Value   (std::forward<ValueType>(Value)),
Exists  (Existance)
{
}
size_t size() const
{
return Value.size();
}
const InputFileVariable & operator=(InputFileVariable && Another)
{
Key     = std::forward<InputFileVariable>(Another).Key;
Value   = std::forward<InputFileVariable>(Another).Value;
Exists  = true;
return *this;
}
template <class ElementType = ValueType::value_type>
const typename ElementType & operator[](size_t Index) const
{
return Value[Index];
}
template <class ElementType = ValueType::value_type>
typename ElementType & operator[](size_t Index)
{
return Value[Index];
}
operator const ValueType & () const
{
return Value;
}
operator ValueType & ()
{
return Value;
}
};

int wmain(int argc, wchar_t *argv[], wchar_t *envp[])
{
// Used with "std::vector":
InputFileVariable<std::vector<int>> MyVar1("MV1", {2, 4, 6, 8}, true);
const size_t SIZE = MyVar1.size();
std::cout << "Size = " << SIZE << std::endl;
int Temp = MyVar1[1];
MyVar1[1] = MyVar1[2];  // Here we call both the const and non-const operators.
MyVar1[2] = Temp;
for (size_t i=0; i<SIZE; i++)
{
std::cout << "MyVar1[" << i << "] = " << MyVar1[i] << std::endl;
}

// Used with "double":
InputFileVariable<double> MyVar2("MV2", 3.14, true);
std::cout << std::endl << "MyVar2    = " << MyVar2 << std::endl;

std::cout << std::endl;
_wsystem(L"timeout /t 60 /nobreak");
return 0;
}

Выход:

Size      = 4
MyVar1[0] = 2
MyVar1[1] = 6
MyVar1[2] = 4
MyVar1[3] = 8

MyVar2    = 3.14
0
По вопросам рекламы [email protected]