【问题标题】:storing arrays of string literals without size - std::initializer_lists存储没有大小的字符串文字数组 - std::initializer_lists
【发布时间】:2022-06-14 01:16:26
【问题描述】:

我正在探索在没有边车大小信息的情况下存储文字数组(任何类型)的方法。我已经勾勒出了一些方法,但对于每一种方法都有一些挥之不去的问题。这里我使用std::initializer_list,而不是模板化std::array。请注意,这是一个简单的测试用例,实际的类可能有额外的成员、额外的模板参数和必须提供的模板参数。

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()};

【问题讨论】:

  • "我正在探索在没有 sidecar 大小信息的情况下存储文字数组(任何类型)的方法。" 你为什么要这样做?未调整大小的数组不是一件好事。
  • 信息还在,只是编译器提供的,而不是用户提供的。
  • 所以这个真正是你想从一个包含括号初始化列表的表达式创建一个auto-deduced变量,没有明确指定该表达式该列表的大小是多少。也就是说,你想要auto lit_list = something{"lit1", "lit2", "lit3"},其中something 没有指定3。

标签: c++ c++20 lifetime literals


【解决方案1】:

让我们通过这一系列问题来分解您想要完成的任务。您似乎希望能够输入以下内容:

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

具有以下限制:

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

您的所有建议都存在缺陷。

initializer_list 失败 #3 因为它由一个临时数组支持(你可以使用它,但你必须非常小心如何传递它们)。 span 因类似原因不可行。 std::array 失败,因为字符串文字实际上不是char const*s,所以你必须明确地说std::array&lt;char const*&gt;。但是如果指定任何模板参数,CTAD 将无法工作。

最后一个是解决方案的关键:您需要一个类似std::array 的类型,但需要一个专门用于char const* 的类型。这样,您不必提供模板参数,CTAD 就可以工作。

最简单的方法是创建一个从std::array 继承的简单类型,并给它一个推导指南,计算你初始化它的元素数量。 C++17 允许聚合具有基类,聚合初始化的大括号省略使您不必使用多个大括号:

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

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

【讨论】:

    猜你喜欢
    • 2022-06-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 1970-01-01
    相关资源
    最近更新 更多