2

我正在解析基于文本的文件以从中读取变量。文件中变量的存在很重要,所以我决定编写一个模板类,它将保存变量的值(Value)及其存在标志(Exists)。重载类下标运算符以访问成员的元素std :: vector对象

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[]直接访问向量的元素。这样我就可以使ValueExists成员保密。

我在代码中使用这个类是这样的:

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'ssongyuanyao's答案是正确的,只有当包含变量类型(即; ValueType)是std::vector。如果我们尝试存储一个基本数据类型(例如:intfloat),编译器(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(Value [Index])&'吗? – hkBattousai

+0

@hkBattousai Nah,在这种情况下'decltype's会像你想要的那样工作。 – TartanLlama

3

您正在返回错误的类型。

对于const Type & operator[](size_t Index) constTypestd::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,并且没有< <运算符重载,它接受cout的std :: vector。

相关问题