在带有std :: string的switch-case块中返回字符串常量

时间:2019-02-04 14:22:37

标签: c++ c++14

注意:这不是关于在转换用例块中使用字符串选择执行路径的。

C ++中的一种常见模式是使用切换用例块将整数常量转换为字符串。看起来像:

char const * to_string(codes code)
{
    switch (code)
    {
        case codes::foo: return "foo";
        case codes::bar: return "bar";
    }
}

但是,我们使用的是C ++,因此使用std :: string更合适:

std::string to_string(codes code)
{
    switch (code)
    {
        case codes::foo: return "foo";
        case codes::bar: return "bar";
    }
}

这将复制字符串文字。也许会有更好的方法:

std::string const & to_string(codes code)
{
    switch (code)
    {
        case codes::foo: { static std::string str = "foo"; return str; }
        case codes::bar: { static std::string str = "bar"; return str; }
    }
}

但这有点丑陋,涉及更多样板。

使用C ++ 14解决此问题的最干净,最有效的解决方案是什么?

3 个答案:

答案 0 :(得分:8)

  

这将复制字符串文字。

是,不是。它将确实复制字符串文字,但是不必分配内存。检查您的实施SSO限制。


您可以使用std::string_view

constexpr std::string_view to_string(codes code) {
    switch (code) {
        case codes::foo: return "foo";
        case codes::bar: return "bar";
    }
}

您可以找到许多向后移植的版本,例如this one

但是,有时char const*是正确的抽象。例如,如果要将该字符串转发到需要以null结尾的字符串的API中,则最好返回一个c样式的字符串。

答案 1 :(得分:2)

  

但这有点丑陋,涉及更多样板。

     

使用C ++ 14解决此问题的最干净,最有效的解决方案是什么?

要回答上述问题,正如@SamerTufail指出的那样(我也是在工作中亲自做的),我将像这样使用table.stylized { font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif; font-size: 12px; text-align: left; border-collapse: collapse; margin: 4px; width: 600px; } table.stylized thead th { text-transform: capitalize; font-size: 13px; color: #039; background: #b9c9fe; padding: 6px; cursor: pointer; } table.stylized tbody tr:nth-child(odd) { background: #f2f5ff; } table.stylized tbody tr:nth-child(even) { background: #e8edff; } table.stylized tbody td { border-top: 1px solid #fff; color: #669; padding: 6px; height: 1.5em; /* Min row height */ } table.stylized tbody tr:hover td { background: #d0dafd; } table.stylized tfoot tr { color: #039; background: #b9c9fe; text-align: right; } s和<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

enum

然后在main()中,您可以得到这样的值,

std::map

我将创建一个用于返回 typedef enum { foo = 1, bar = 2, } Key; std::map<Key, std::string> hash_map = { {Key::foo ,"foo"}, { Key::bar,"bar"} }; 的函数,您将在其中检查std::cout << hash_map.find(Key::foo)->second; 的迭代器,否则该插入器将无效并且使用它将是UB。


编辑:正如其他人在评论中指出的那样,并且根据此question,如果不需要,您可以将second替换为end()使元素保持秩序。

根据我的经验,我总是创建std::map这样的地图。因此,一次创建它们,并多次使用它们摊销创建成本。

答案 2 :(得分:0)

假设您最终想要一个带有标签的std::string,那么问题是是否要创建它们:

1:在to_string()
 2:在呼叫者中

使用Compiler Explorer很容易发现。

证明(使用最新的编译器)两者之间没有太大区别。返回const char *std::string

上有一点优势

1:

#include <string> 

char const * to_string(int code)
{
    switch (code)
    {
        case 0: return "foo";
        case 1: return "bar";
    }
}

std::string foo(int x)
{
    std::string s{to_string(x)};
    return s;    
}

2:

#include <string> 

std::string to_string2(int code)
{
    switch (code)
    {
        case 0: return "foo";
        case 1: return "bar";
    }
}


std::string foo2(int x)
{
    std::string s{to_string2(x)};
    return s;    
}

注意:

  • 我需要添加foo()才能阻止编译器进行更大的优化。...
  • 在两种情况下,字符串都很短,可以使用短字符串优化。 clang和GCC都已完成了 heap-elision 。这是非常令人印象深刻的-编译器知道to_string()永远不会返回大于4个字节长的字符串,然后消除了将动态分配堆内存的代码。

结论似乎是,编写自然而整洁的代码几乎不会降低性能。