已知序列的 std::vector

Posted

技术标签:

【中文标题】已知序列的 std::vector【英文标题】:std::vector of known sequences 【发布时间】:2009-12-17 00:21:25 【问题描述】:

我正在尝试通过“以 C++ 方式”做所有事情来学习 C++。我正在编写一个程序,其中我拥有所有这些已知值(在编译时)。这是我的问题:

在我的构造函数中,我想检查传递的值(一个 int)是否是 2、4、8、16 或 32 之一,否则会抛出错误。我虽然是:

    制作 C 风格的数组或整数 之前手动创建一个向量并通过它进行交互以检查 列出清单?不过,我以前从未使用过列表。

我真正想做的是在单独的头文件中创建一个 const 向量,但这似乎是不可能的。

进行这项检查最优雅的方法是什么?

另外,类似地,有什么方法可以在标头中创建一个具有一组已知值(在编译时)的向量?如果我能做到const std::string a_str("a string");,我不明白为什么我不能对向量使用类似的技术。

【问题讨论】:

“我不明白为什么我不能对向量使用类似的技术。”类的初始化列表。我相信这是计划中的“c++0x”功能。还没有标准... 【参考方案1】:

有什么问题:

if (!(n == 2 || n == 4 || n == 8 || n == 16 || n == 32))

    // no!

如果你想要“C++ 方式”,静态数组应该可以,find:

template <typename T, size_t N>
T* endof(T (&pArray)[N])

    return &pArray[0] + N;


static const int OkNumbers[] = 2, 4, 8, 16, 32;
static const int* OkNumbersEnd = endof(OkNumbers);
if (std::find(OkNumbers, OkNumbersEnd, n) == OkNumbersEnd)

    // no!

修改这个列表很简单,我猜编译器可能将它优化为我之前的答案。

【讨论】:

他想用“C++ 方式”来做 这不是 C++ 代码吗?我认为,任何仅仅为了检查几个数字而设置列表的人都做了太多的工作。 我没有说这不是 C++,他说他想用“C++ 方式”来做这件事,这应该是什么意思。我同意这是太多的工作,但他可能只是为了锻炼而这样做 代替endof 方法,试试这个:OkNumbersEnd = OkNumbers + sizeof(OkNumbers) / (OkNumbers[0]); 可以在编译时计算,不需要模板。 您的代码更冗长,而我的代码也是编译时间。模板并不是一件坏事。【参考方案2】:

这有点花招,但我相信这行得通:

if (n & (n-1) != 0)

   // not a power of two

【讨论】:

我认为他只想要 OP 中列出的 5 个数字。也许范围检查会使其合适。 0 == 0x0000 不是二的幂。 (0-1) == -1 == 0xffff0x0000 &amp; 0xffff == 0x0000 == 0 不是 != 0。所以你的逻辑有缺陷。 hhafez:嗯,添加一个(n &gt; 32) 比较是微不足道的。 如果您想排除 64 和更大(和 1),您可以轻松地明确检查这些。 if(n &amp; (n - 1) &amp;&amp; n &gt;= 2 &amp;&amp; n &lt;= 32) 比显式检查所有值的替代方法更简洁(并且可维护 - 如果我们以后想要允许 64、128、256 等怎么办?)。 +1 @ndim - 这不是一个完美的检查,但它可能比针对每个特定值进行测试更有效(并且更容易维护)。【参考方案3】:

如果我们谈论的是有点愚蠢,这是我的尝试:

if ((n & 0x3E) != n || (n & n - 1) != 0)
  throw std::runtime_error("not a power of two less than or equal to 32");

有点笨拙是非常 C/C++,但只有“优雅”,如果你所说的优雅是指“尽可能少的处理器周期和尽可能简洁的语法”。否则使用字典查找或显式检查(例如 GMan 的答案中的 std::find )。

可读性几乎总是比这种古怪更可取。

【讨论】:

【参考方案4】:

如果你真的想用向量来做,并且想要好的赋值操作,看看 boost::assign。

但你真的不想用矢量来做这件事;)

编辑:我刚刚看到您的“编译时”。考虑为什么不能这样做:std::vector 不是内置类型。要拥有一种使用某种智能分配的机制,需要为整个语言和每个用户定义的类型内置对它的支持。即使您不需要核心语言支持并且可以使用模板来做到这一点,这也不符合 STL 的整体风格。

【讨论】:

std::string 不是内置类型,您在问题中提供的代码不会在编译时创建字符串。它在运行时创建一个字符串,并使用 C 风格的字符串文字对其进行初始化。 std::string 恰好有初始化它的好方法,而向量没有。 C++0x 将引入初始化列表,它可以让你做std::vector&lt;int&gt; v = 1, 2, 3;std::vector&lt;std::string&gt; v2 = "1", "2", "3"; 没有。您要引用的构造函数将 const char* 作为参数。该指针取自字符串文字“a string”。字符串文字是“内置的”。 是的,但是当 devin 说“字符串是内置类型”时,答案必须是“否”。通过“字符串”,他的意思是“std::string”(不是内置类型),或者他的意思是“字符串文字”(根本不是类型)。在我上面的评论中,我说“string”的任何地方都是“std::string”,除了我说“C-style string literal”的地方。【参考方案5】:

使用一个普通的 C 数组,我的 C 已经生锈了,但是这里可以

int array[] = 2,4,8,16,32;

/* now loop over the array and check */

for( i = 0; i< size_of_array ; i++) 
  if (array[i] == input_int) 
  /* you get the idea ..... */

【讨论】:

【参考方案6】:

这可能不适合您要执行的操作的上下文,但您可以使用枚举。

由于这是编译时的知识,我假设这些传递的值在编译时很重要。使用枚举,调用者不会试图找出要传递给您的函数的幻数。

typedef enum 

  Value1 = 2,
  Value2 = 4,
  Value4 = 8,
  Value5 = 16,
  Value6 = 32

 MyMagicType;

void MyFunction(MyMagicType theType)

...

然后编译器将强制该值是上述之一(好吧,除非你强制转换它,但那是另一回事)并在它不是定义的值之一时抛出错误。

【讨论】:

以上是关于已知序列的 std::vector的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 boost::serialization 序列化 std::vector?

如何使用 boost std::vector of boost::unordered_map 进行序列化/反序列化

序列化 std::vector 以提升二进制存档时的数据相关失败

指针向量。 BOOST 序列化

序列容器-元素只能按顺序访问

如何将向量序列化为字符数组