2

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

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>>' (или нет приемлемой конверсии)

Что я здесь делаю неправильно?

+0

Вы можете посмотреть на 'optional' (который не требует, чтобы' type' по умолчанию конструктивна). – Jarod42

ответ

0

TartanLlama's и songyuanyao's правильные ответы только тогда, когда содержится тип переменной (т.е. .; 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 
4
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]; 
} 
+0

Это работает. Спасибо. Должен ли я изменить 'decltype (Value [Index])' на 'const decltype (Value [Index]) &' и 'decltype (значение [Index]) &' соответственно? – hkBattousai

+0

@hkBattousai Nah, 'decltype's будет работать так, как вы хотите в этом случае. – TartanLlama

3

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

Для 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 
2

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

const Type & operator[](size_t Index) const 

Но AVector объявлен

const MyVariable<std::vector<int>> 

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