如何将 C 数组转换为 std::initializer_list?
Posted
技术标签:
【中文标题】如何将 C 数组转换为 std::initializer_list?【英文标题】:How to convert C array to std::initializer_list? 【发布时间】:2019-10-22 02:02:28 【问题描述】:我知道指向数组的指针及其大小。可以从中创建什么容器?我试着这样做:
std::initializer_list<int> foo(arr, arr + size);
它适用于 MSVC,但不适用于 gcc
【问题讨论】:
Initializer_list
构造函数非常简单:constexpr initializer_list() noexcept;
。如果std::initializer_list<int> foo(arr, arr + size);
在 Visual Studio 下工作,那是因为他们添加了扩展。
initializer_list
设计用于大括号时间列表,它不是通用容器。您可以使用vector
或span
以及其他选项
这个列表的最终目标是什么?在需要之前传递数组和长度可能更容易。如果没有,我会从 std::vector
开始,可能会完全放弃数组。
引出一个问题:为什么不首先使用std::vector
?无论如何,如果您以后只是要将它填充到容器中,那么该数组有什么用?
一个重要的补充——我不想复制内存。 MSVC 的 initializer_list 只是提供了一个用于遍历数组的接口。
【参考方案1】:
std::initializer_list
是专为支持列表初始化而设计的引用类型,只有 default-ctor 和隐式 copy-ctor。任何其他 ctor 都是扩展。
您可以做的是直接从迭代器范围初始化目标容器,而不涉及任何中间视图。
除非您更清楚,否则要使用的标准容器是std::vector
。或者使用像std::span
这样的简单视图就足够了?
【讨论】:
std::span
正是我正在寻找的。谢谢!【参考方案2】:
如果您需要一个实际的数据拥有容器,那么您需要的是std::vector
。这将花费您一份副本和一份分配的费用。如果您只需要像容器一样工作,那么您想要的是来自 C++20 的即将推出的std::span
。它接受一个指针和一个大小,并将其包装在一个类似于数组的接口中。
MSVS 的使用
std::initializer_list<int> foo(arr, arr + size);
不是标准的。 Per the standard std::initiliazer_list
的唯一构造函数是
constexpr initializer_list() noexcept;
【讨论】:
跨度在这里太过分了。您可以从arr, arr + size
创建任何容器。
@NicolBolas 所有这些都会复制。跨度是“零成本”。
OP 问道,“可以从中创建什么容器?” span
不是容器。 initializer_list
只是达到目的的一种手段。
@NicolBolas Goiod 点。它列在[containers] 下,这让我很震惊。【参考方案3】:
这里有两个问题,每个问题都有自己的答案。
如何将 C 数组转换为 std::initializer_list?
你不能。这样做真的没有意义。 std::initializer_list
实际上只用于初始化(顾名思义)对象。它基本上是从 符号创建的,如下所示:
myObject obj = 0,1,2,3,4;
尝试创建 std::initializer_list
的实例在我能想到的任何其他意义上都没有真正的用处,尤其是因为 C++14 it's impossible to create at runtime 无论如何,因为它有一个 constexpr
构造函数。
如果你有一些对象foo
接受std::initializer_list
,像这样:
class foo
foo(std::initializer_list list)
//...
;
而你想知道如何在没有std::initializer_list
的情况下创建这个对象,那么答案就是简单地添加另一个构造函数:
class foo
// an actual array
foo(type arr[size])
//...
// as a pointer
foo(type arr*, size_t size)
//...
;
如果您正在使用第三方库,或者您无法控制的其他库,并且没有其他构造函数,那么很可能它不打算以这种方式使用。在这种情况下,我会咨询您的文档或供应商。
可以从中创建什么容器?
任何sequence container。它们中的大多数都有某种构造函数,它接受指向对象的指针(实际上,它在技术上采用迭代器,但指针在这种情况下的工作方式相同)或数组。它们几乎是为从 C 数组轻松转换而设计的。您使用哪一种取决于您的情况。
此外,std::span
(未列为“序列容器”)已被提及为可以从 C 数组以低成本创建的可能容器。不过,我不能亲自为他们担保,因为我对即将推出的标准不太熟悉。
最后说明:如果 MSVC 允许这样做,那么 a) 你可能在 C++11 中(尽管我无法确认 C++11 中是否允许这样做,只是构造函数不是 @987654336 @ 在 C++ 中)或 b)它是 MSVC 中的编译器错误。
【讨论】:
"你想知道如何在没有 std::initializer_list 的情况下创建这个对象,那么答案就是简单地添加另一个构造函数:" - 我可以在 tensorflow 内部类中做到这一点吗?他们只有std::initializer_list 作为输入,他们制作 - 没有其他。为什么 ??为什么从任何容器创建一个 std::initializer_list 构造器这么难?以上是关于如何将 C 数组转换为 std::initializer_list?的主要内容,如果未能解决你的问题,请参考以下文章