【问题标题】:Enum with constexpr std::string_view vs instantiated enum with std::string带有 constexpr std::string_view 的枚举与带有 std::string 的实例化枚举
【发布时间】:2018-04-01 12:35:08
【问题描述】:

我想让structs 持有enums 进行迭代,同时std::string 持有他们的名字以创建菜单条目。我正在使用这样的东西:

struct S
{
    enum E { ONE, TWO, ALL };
    std::array<std::string, ALL> names { "one", "two" };
};
int main()
{
    S s;
    for(int i=s.ONE; i<s.ALL; ++i) // or S::...
        std::cout << s.names[i] << '\n';
    return 0;
}

据我了解,这比使用全局变量更可取。它可以工作,但需要在使用前进行实例化。现在,我发现了这个方法,需要--std=C++17编译:

struct S
{
    enum E { ONE, TWO, ALL };
    static constexpr std::array<std::string_view, ALL> names { "one, "two" };
};
int main()
{
    for(int i=S::ONE; i<S::ALL, ++i)
        std::cout << S::names[i] << '\n';
return 0;
}

但是,与我之前的操作方式相比,在内存使用方面,这将如何表现?还是我的做法有误?有什么更好的方法?

【问题讨论】:

    标签: c++ enums static constexpr


    【解决方案1】:

    在使用std::array 时,您不需要那个enum。你可以这样做:

    struct S
    {
        static constexpr std::array<std::string_view, 2> names { "one", "two" };
    };
    
    int main()
    {
        for(auto name: S::names)
            std::cout << name << '\n';
    }
    

    或者这个:

    int main()
    {
        for(auto n = std::begin(S::names); n != std::end(S::names); ++n)
            std::cout << *n << '\n';
    }
    

    这与您的第一个示例非常不同,因为现在您只有 one 数组用于 every sruct S。以前,每个结构都有自己的数组副本。

    所以做适合您需要的事情。每个对象一个数组?或者一个数组用于所有您的对象?

    【讨论】:

    • 不幸的是,我并不总是需要所有的条目,有些可能会被跳过,所以我并不总是使用for() 循环,或者有时它是有限的for(int i=S::THREE; i&lt;S::SEVEN; ++i)
    • @aconcernedcitizen 你可以这样做:for(auto i = std::begin(S::names) + 2; i &lt; std::begin(S::names) + 6; ++i) {}
    • 当然我宁愿尽量减少内存使用,但它可能不那么可读,这就是enum的原因。尽管如此,尽管使用了std::beginstd::end,您似乎也使用了struct,同样,您只需放弃enum。如果我使用enum,然后按照您的建议使用for(auto i=std::begin(S::names)+S::TWO; ...),那么无论有多少for() 循环调用它,这是否与内存中只有一个数组一样有效?
    • @aconcernedcitizen 老实说,我不确定std::begin(S::names) + S::TWO 是否比std::begin(S::names) + 2 更清晰。但这取决于你。
    • 我可能也有一些疑问,但更像是S::LEGENDRE。尽管如此,这似乎是减少过多 objestc 的好方法(我试图用这个新方法来避免这种情况,而不是为每种情况实例化一个对象)。
    【解决方案2】:

    您的要求并不完全清楚,但除了您的示例中的一些小错误之外,这很好。

    如果我们稍微更改示例以不使用 iostream(因为它与汇编列表中的大量代码混淆)。一个例子,而不是对名称的大小求和:

    #include <string_view>
    #include <array>
    
    struct S
    {
        enum E { ONE, TWO, ALL };
        static constexpr std::array<std::string_view, ALL> names { "one", "two" };
    };
    int main()
    {
        int l=0;
        for(int i=S::ONE; i<S::ALL; ++i){
            l+= S::names[i].size() ;                 
        }
    
    return l;
    }
    

    它编译成一些代表“return 6”的汇编指令。但是,正如 Galik 指出的那样,不需要枚举技巧。

    https://godbolt.org/g/ot2kpt

    您还可以选择一个范围进行循环,如下所示:

    for(auto n = std::begin(S::names)+1; n != std::end(S::names); ++n)
    

    【讨论】:

    • 抱歉有错误,我只是凭记忆打出来的。
    猜你喜欢
    • 2013-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-02
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多