【问题标题】:Construct std::set from array从数组构造 std::set
【发布时间】:2013-08-28 17:14:57
【问题描述】:

为什么 C++ 不为我们提供一个将数组作为参数的构造函数?或者,定义以下函数有什么问题吗?

template <class T>
std::set<T> ArrayToSet(T array[]) {
  return std::set<T>(array, array + sizeof(array) / sizeof(array[0]));
}

我认为答案可能归结为动态内存分配的想法,但我想听听对此的一些反馈。

编辑:我没有使用 C++11。

【问题讨论】:

  • 使用迭代器一。
  • " 定义下面的函数有什么问题吗?"是的,它总是 100% 错误。

标签: c++ arrays stl set


【解决方案1】:

另外,定义以下函数有什么问题吗?

有:它不起作用。

您不能将可变长度的 C 样式数组传递给函数。参数列表中的 T array[] 语法是 T* array 的同义词:传递的是 原始指针,而不是参数。

但是,您可以通过引用传递固定大小的数组(即T (&amp;array)[5] 有效)。要使其适用于不同的数组长度,您需要使用非类型模板参数:

template <class T, std::size_t N>
std::set<T> ArrayToSet(T (&array)[N]) {
  return std::set<T>(array, array + N);
}

– 但我同意 Zac 的观点:函数过于具体(或者,反过来:不够通用)。已经有一个通用的集合构造方法,通过迭代器。所以正确的做法是使用C++11的std::beginstd::end设施,如果不能使用C++11,那么正确的做法是自己写:

template <typename T, std::size_t N>
T* begin(T (&array)[N]) {
    return array;
}

template <typename T, std::size_t N>
T* end(T (&array)[N]) {
    return array + N;
}

【讨论】:

  • 也可以显示使用情况:std::set&lt;T&gt;(begin(array),end(array)).
  • 似乎一致认为创建 begin() 和 end() 函数是问题的正确答案,而不是转换函数。
【解决方案2】:

为什么 C++ 不为我们提供一个以数组为参数的构造函数 争论?

为什么会这样? std::set 不是一个数组,它已经有一个构造函数,它使用迭代器来初始化它,因此不需要为数组添加另一个构造函数。 std::vector 是一个数组,即使它没有接受数组的构造函数。

或者,定义以下内容有什么问题吗 功能?

是和不是。没必要,直接写就行了

MyType myArray[mySize];
std::set<MyType> mySet(myArray, myArray + sizeof(myArray) / sizeof(array[0]);
// or std::set<MyType> mySet(myArray, myArray + mySize);
// or std::set<MyType> mySet(std::begin(myArray), std::end(myArray)); c++11

它并不真正值得拥有自己的功能。

如果您真的想编写一个函数来帮助您,我会通过将std::beginstd::end 移植到C++03 来实现它。这些至少比专门用于创建std::set 的函数更有用。

这看起来与康拉德在他的回答中发布的完全一样。

【讨论】:

  • 它完全值得自己的功能,但OP的功能不起作用。
  • 关于为什么没有构造函数已经足够公平了。我想要这个函数的原因是我打算经常这样做,并且拥有一个函数可以节省拼写错误。我希望能够使用 C++11 初始化程序列表,但这不是一个选项...
  • @KonradRudolph:你打算为你声明的每个变量类型编写一个单行函数吗?上帝啊,我希望永远不必查看您的代码...
  • @KonradRudolph:C++11 专用于 std::beginstd::end,因为数组没有成员,所以我们可以编写适用于数组的通用“容器”代码。写array+lenIMO>时与防止错误无关
  • 顺便添加的代码不行,指针的sizeof返回的是指针的大小,不是数组大小。
【解决方案3】:

std::set 不需要为 C 样式数组提供构造函数,因为可以使用迭代器从它们构造 - 此外,从数组构造并不容易,因为您可以尝试从 @987654322 构造@,它不传达数组长度,或者它是否是一个数组。

为此,我们使用模板技巧来确定数组大小并使用迭代器构造函数:

template <typename T, size_t N>
std::set<T> ArrayToSet(T (& array)[N]) {
    return std::set<T>(&array[0], &array[0]+N);
}

请注意,正如 cmets 中所述,这不适用于 T * 类型。您可以为此提供额外的参数arr_length 或其他东西。在这种情况下,sizeof 也不起作用,它只会给你指针的大小,而不是数组。

【讨论】:

  • 我已更新声明我没有使用 C++11。你能解释一下为什么我们需要“偷偷摸摸”吗?谢谢
  • 对于非C++11版本,我会实现beginend
  • 除非我错过了最新标准中的某些内容,否则模板参数需要在编译时完全确定,因此只要您提前知道大小,这里的模板版本就可以工作,但会不适用于动态大小的数组。
  • @ZacHowland 没错;以及您想改用std::vector 的充分理由
  • &amp;array[N] 无效。不允许您访问array[N],即使您之后立即使用指针。至少在某些版本的 VC++ 中,这在运行时会失败,并且可能在其他编译器中也是如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-23
  • 1970-01-01
  • 2011-01-25
  • 2011-06-06
  • 2019-07-06
  • 2021-05-22
  • 1970-01-01
相关资源
最近更新 更多