重载 class 下标运算符以访问成员 std::vector 对象的元素
Overloading the class subscript operator to access elements of a member std::vector object
我正在解析一个基于文本的文件以从中读取变量。文件中变量的存在很重要,所以我决定编写一个模板 class,它将保存变量的值 (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[]
来直接访问vector的元素。这样我就可以将 Value
和 Exists
成员设为私有。
我在代码中这样使用 class:
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.
}
我收到以下错误消息:
Error C2679 binary '<<'
: no operator found which takes a right-hand operand of type 'const std::vector<int,std::allocator<_Ty>>'
(or there is no acceptable conversion)
我做错了什么?
const Type & operator[](size_t Index) const
{
return Value[Index];
}
Type & operator[](size_t Index)
{
return Value[Index];
}
那些return类型是错误的;您正在 returning 包含的类型,而不是容器类型。您可以为此使用 decltype
:
auto operator[](size_t Index) const -> decltype(Value[Index])
{
return Value[Index];
}
auto operator[](size_t Index) -> decltype(Value[Index])
{
return Value[Index];
}
您 return 输入错误类型。
对于const Type & operator[](size_t Index) const
,Type
是std::vector<int>
,这意味着你试图return一个vector
,而不是[=的元素14=].
尝试将return值的类型改为typename Type::value_type
,如
const typename Type::value_type& operator[](size_t Index) const
您的运算符重载已声明
const Type & operator[](size_t Index) const
但是 AVector 声明为
const MyVariable<std::vector<int>>
所以 Type
在你的情况下是 std::vector,并且没有 << 运算符重载接受 std::vector 用于 cout。
and 只有当包含的变量类型(即 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
我正在解析一个基于文本的文件以从中读取变量。文件中变量的存在很重要,所以我决定编写一个模板 class,它将保存变量的值 (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[]
来直接访问vector的元素。这样我就可以将 Value
和 Exists
成员设为私有。
我在代码中这样使用 class:
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.
}
我收到以下错误消息:
Error C2679 binary
'<<'
: no operator found which takes a right-hand operand of type'const std::vector<int,std::allocator<_Ty>>'
(or there is no acceptable conversion)
我做错了什么?
const Type & operator[](size_t Index) const
{
return Value[Index];
}
Type & operator[](size_t Index)
{
return Value[Index];
}
那些return类型是错误的;您正在 returning 包含的类型,而不是容器类型。您可以为此使用 decltype
:
auto operator[](size_t Index) const -> decltype(Value[Index])
{
return Value[Index];
}
auto operator[](size_t Index) -> decltype(Value[Index])
{
return Value[Index];
}
您 return 输入错误类型。
对于const Type & operator[](size_t Index) const
,Type
是std::vector<int>
,这意味着你试图return一个vector
,而不是[=的元素14=].
尝试将return值的类型改为typename Type::value_type
,如
const typename Type::value_type& operator[](size_t Index) const
您的运算符重载已声明
const Type & operator[](size_t Index) const
但是 AVector 声明为
const MyVariable<std::vector<int>>
所以 Type
在你的情况下是 std::vector,并且没有 << 运算符重载接受 std::vector 用于 cout。
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