假设我有以下数据结构:
std::map<size_t, double[2] > trace;
如何使用operator []?
访问其元素基本上我想做类似的事情:
trace[0][0] = 10.0;
trace[0][1] = 11.0;
在编译这些代码行时,我收到以下错误:
/usr/include/c++/4.6/bits/stl_map.h:453:11: error: conversion from ‘int’ to non-scalar type ‘std::map<long unsigned int, double [2]>::mapped_type {aka double [2]}’ requested
评论
答案 0 :(得分:5)
地图的值类型必须是默认可构造的,使用表达式value_type()
才能通过[]
访问它们。出于一些神秘的原因,数组类型不是,如C ++ 11 5.3.2 / 2中所规定的那样(我强调):
表达式T(),其中T是非数组完整对象类型的简单类型说明符或类型名称说明符...创建指定类型的prvalue,这是价值初始化
编译器在尝试对数组进行值初始化时会发出奇怪的错误;以下内容给出了同样的错误:
typedef double array[2];
array();
我建议使用类型而不是double[2]
:std::array<double,2>
,std::pair<double,double>
或包含两个双打的struct
。这些类型是可复制的,不会在一滴一滴的情况下衰减成指针(失去编译时的大小知识),并且通常比内置数组类型更容易处理。
如果您遇到一个不提供std::array
的旧库,那么您可以使用非常相似的Boost.Array,或者编写自己的简单类模板来包装数组。
答案 1 :(得分:1)
你可以包装一个数组:
template<typename T, unsigned int n>
struct ArrayWrapper
{
T v[n];
T& operator[](unsigned int i) { return v[i]; } // You can also check for out-of-bounds errors
const T& operator[](unsigned int i) const { return v[i]; } // You can also check for out-of-bounds errors
};
#include <map>
#include <iostream>
int main()
{
typedef std::map<size_t, ArrayWrapper<double,2> > Map;
Map trace;
trace[1][0] = 42;
for(Map::const_iterator it = trace.begin(); it != trace.end(); ++it)
std::cout << "( " << (*it).first
<< ", " << (*it).second[0]
<< ", " << (*it).second[1]
<< ")\n";
}
Live example。否则,如果你有C ++ 11,你应该使用std::array
;如果没有,并且你有Boost,你可以使用Boost.Array。
答案 2 :(得分:1)
你的代码编译到:
std::map<size_t, double[2]> trace;
因为double[2]
是有效类型。您可以使用任何有效类型声明模板类对象。例如:
template<typename T>
struct X {
// T t; // this will complain for sure
void foo () { T t; } // this won't complain unless invoked !!
};
X<void> x;
将编译没有任何问题。
如果你调用x.foo()
,编译器会抱怨它。
std::map
的情况也是如此。当您调用map::insert()
,map::operator []
等函数时,实际将使用值类型double[2]
,编译器将开始抱怨,因为double[2]
不可复制(异常:我见过一个旧的g ++ 3.x版本,其中数组是可分配和可复制的。)
您可以将数组封装到结构中。
struct D { double d[2]; };
如果你想避免使用原始数组,那么std::array
是很好的选择,如评论和其他答案所述。