存储字符串文字的数组,没有大小-STD :: pritializer_lists

发布于 2025-02-06 20:43:11 字数 1216 浏览 2 评论 0原文

我正在探索用于存储文字阵列(任何类型)的方法,而无需侧尺尺寸信息。我绘制了一些方法,但是每个方法都有一些挥之不去的问题。在这里,我使用std :: prinitizer_list,而不是通过std ::数组进行模板。请注意,这是一个简单的测试用例,实际类可能具有其他成员,其他模板参数和必须提供的模板参数。

struct B {
    std::initializer_list<const char*> a;
    int b;
};

// Helper for the question
constexpr std::initializer_list<const char*> get1() {
    // Confirm: string literals, lifespan OK?
    return {"1", "2", "3"};
}

由于我正在处理文字值(存储在代码中),因此为什么不使用初始化器列表对象而不是通过std :: array模板?虽然列表不拥有其内容的所有权,但作为字面价值观,它们永远不会出现。此外,不必指定列表尺寸 - 无论大小如何,都不需要模板。唯一的问题是缺乏下标操作员,导致详细的代码略有。使用初始化列表的绝妙想法来自IRC。看看我能做的所有整洁的事情:

auto b = B{{"1","2","3"}};
auto b = B{get1()};

std::cout << b.a.begin()[2] << ", size: " << b.a.size() << std::endl;

for (auto& e: b.a) { std::cout << e << std::endl; }

auto l = [](const char* s) { return !strcmp(s, "2"); };
auto r = std::find_if(begin(b.a), end(b.a), l);
std::cout << "result: " << *r << std::endl;

初始化列表的基础存储是字符串文字吗?由于字符串文字是全局的,因此初始化列表是否在程序的持续时间内有效?请参阅以下示例。我有悬挂指针的风险吗?如果没有,我该如何使警告保持沉默?

auto b = B{{"1","2","3"}};
auto b = B{get1()};

I am exploring methods for storing arrays of literals (any type) without sidecar size information. I've sketched some approaches but for each have some lingering questions. Here I use std::initializer_list rather than templating over std::array. Please note that this is a simple test case and that actual classes might have additional members, additional template parameters, and template parameters that must be provided.

struct B {
    std::initializer_list<const char*> a;
    int b;
};

// Helper for the question
constexpr std::initializer_list<const char*> get1() {
    // Confirm: string literals, lifespan OK?
    return {"1", "2", "3"};
}

Since I'm dealing with literal values (stored in the code), why not use an initializer list object rather than templating over an std::array? While the list won't have ownership of its contents, as literal values they'll never go out-of-scope. Furthermore the list size need not be specified - regardless of size, no template is required. The only problem is the lack of a subscript operator, leading to slightly more verbose code. The brilliant idea of using initialization lists came from IRC. Look at all the neat things I can do:

auto b = B{{"1","2","3"}};
auto b = B{get1()};

std::cout << b.a.begin()[2] << ", size: " << b.a.size() << std::endl;

for (auto& e: b.a) { std::cout << e << std::endl; }

auto l = [](const char* s) { return !strcmp(s, "2"); };
auto r = std::find_if(begin(b.a), end(b.a), l);
std::cout << "result: " << *r << std::endl;

Is the underlying storage of the initialization list the string literals? Since string literals are global, will the initialization list be valid for the duration of the program? See the following examples. Am I at risk of dangling pointers? If not, how do I silence the warning?

auto b = B{{"1","2","3"}};
auto b = B{get1()};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

似最初 2025-02-13 20:43:11

让我们分解您试图通过这一系列问题实现的目标。您似乎希望能够按照以下方式键入某些内容:

TypeId var_name = Syntax{<list of literals>};

具有以下限制:

  1. &lt; 中的元素数量不应写入type> type> type> >或语法。应该从上下文中推导。
  2. var_name应该能够通过数组语法访问文字。
  3. 您应该能够像其他任何变量一样传递并返回var_name,而不必担心它所引用/包含的数组的所有权。

关于其中一些建议,您的所有建议都是有缺陷的。

initializer_list失败#3,因为它是由临时数组支持的(您可以使用它,但是您必须非常谨慎地将它们传递给它们)。 span由于类似原因是不可行的。 std :: array失败,因为字符串文字实际上不是char const* s,因此您必须明确说std :: array&lt; char&lt; char const*&gt; < /代码>。但是,如果指定了任何模板参数,则CTAD无法工作。

最后一个是解决方案的关键:您需要一种类型,例如std :: Array,但一个专门针对char> char const*。这样,您就不必提供模板参数,因此CTAD可以工作。

最简单的方法是制作一种简单的类型,该类型从std :: Array中继承,并给它一个扣除指南,以计算您初始化的元素的数量。 C ++ 17允许聚合具有基础类,而汇总初始化的撑杆elision则可以使您不必使用多个括号:

template<std::size_t sz>
struct str_array : std::array<char const*, sz>{};

template<typename ...Ts>
str_array(Ts...) -> str_array<sizeof...(Ts)>;

Let's break down what it is that you're trying to accomplish with this series of questions. You seem to want to be able to type something along the lines of:

TypeId var_name = Syntax{<list of literals>};

With the restrictions that:

  1. The number of elements in <list of literals> should not be written into TypeId or Syntax. It should be deduced from context.
  2. var_name should be able to access the literals via array syntax.
  3. You should be able to pass around and return var_name like any other variable without worrying about ownership of the array it references/contains.

All of your suggestions are flawed with respect to some of these.

initializer_list fails #3 because it is backed by a temporary array (you can use it, but you have to be very careful about how you pass them around). span is non-workable for similar reasons. std::array fails because string literals are not actually char const*s, so you have to explicitly say std::array<char const*>. But CTAD cannot work if any template parameter is specified.

That last one is the key to the solution: you need a type like std::array but one specifically for char const*. That way, you don't have to provide template parameters, so CTAD can work.

The easiest way to do that is to make a simple type that inherits from std::array and give it a deduction guide that counts the number of elements you initialize it with. C++17 allowed aggregates to have base classes, and aggregate initialization's brace elision keeps you from having to use multiple braces:

template<std::size_t sz>
struct str_array : std::array<char const*, sz>{};

template<typename ...Ts>
str_array(Ts...) -> str_array<sizeof...(Ts)>;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文