文字中的静态std :: string对象的宏 [英] Macro for static std::string object from literal

查看:126
本文介绍了文字中的静态std :: string对象的宏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我需要调用函数foo,该函数需要在代码中的很多地方获取const std::string引用:

Suppose I need to call a function foo that takes a const std::string reference from a great number of places in my code:

int foo(const std::string&);
..
foo("bar");
..
foo("baz");

使用这样的字符串文字调用函数将创建临时的std::string对象,每次都复制文字.

Calling a function with a string literal like this will create temporary std::string objects, copying the literal each time.

除非我弄错了,否则编译器不会通过为每个文字创建一个静态的std::string对象来优化此效果,该对象可用于后续调用.我知道g ++具有高级的字符串池机制,但是我认为它不会扩展到std::string对象本身.

Unless I'm mistaken, compilers won't optimize this by creating a static std::string object per literal that can be reused for subsequent calls. I know that g++ has advanced string pool mechanisms, but I don't think it extends to the std::string objects themselves.

我可以自己进行优化",这会使代码的可读性降低:

I can do this "optimization" myself, which makes the code somewhat less readable:

static std::string bar_string("bar");
foo(bar_string);
..
static std::string baz_string("baz");
foo(baz_string);

使用Callgrind,我可以确认这确实可以提高程序速度.

Using Callgrind, I can confirm that this does indeed speed up my program.

我以为我会为此做一个宏,但我不知道是否有可能.我想要的是这样的:

I thought I'd try to make a macro for this, but I don't know if it's possible. What I would want is something like:

foo(STATIC_STRING("bar"));
..
foo(STATIC_STRING("baz"));

我尝试使用文字作为模板参数创建模板,但是事实证明这是不可能的.而且由于不可能在代码块中定义函数,所以我全都没主意.

I tried creating a template with the literal as a template parameter, but that proved impossible. And since a function definition in a code block isn't possible, I'm all out of ideas.

是否有一种优雅的方法可以做到这一点,还是我不得不求助于可读性较低的解决方案?

Is there an elegant way of doing this, or will I have to resort to the less readable solution?

推荐答案

您可以使用类似的方法来创建static std::string 就地" :

You may use something like to create your static std::string "in place":

#include <cstdint>
#include <string>

// Sequence of char
template <char...Cs> struct char_sequence
{
    template <char C> using push_back = char_sequence<Cs..., C>;
};

// Remove all chars from char_sequence from '\0'
template <typename, char...> struct strip_sequence;

template <char...Cs>
struct strip_sequence<char_sequence<>, Cs...>
{
    using type = char_sequence<Cs...>;
};

template <char...Cs, char...Cs2>
struct strip_sequence<char_sequence<'\0', Cs...>, Cs2...>
{
    using type = char_sequence<Cs2...>;
};

template <char...Cs, char C, char...Cs2>
struct strip_sequence<char_sequence<C, Cs...>, Cs2...>
{
    using type = typename strip_sequence<char_sequence<Cs...>, Cs2..., C>::type;
};

// struct to create a std::string
template <typename chars> struct static_string;

template <char...Cs>
struct static_string<char_sequence<Cs...>>
{
    static const std::string str;
};

template <char...Cs>
const
std::string static_string<char_sequence<Cs...>>::str = {Cs...};

// helper to get the i_th character (`\0` for out of bound)
template <std::size_t I, std::size_t N>
constexpr char at(const char (&a)[N]) { return I < N ? a[I] : '\0'; }

// helper to check if the c-string will not be truncated
template <std::size_t max_size, std::size_t N>
constexpr bool check_size(const char (&)[N])
{
    static_assert(N <= max_size, "string too long");
    return N <= max_size;
}

// Helper macros to build char_sequence from c-string
#define PUSH_BACK_8(S, I) \
    ::push_back<at<(I) + 0>(S)>::push_back<at<(I) + 1>(S)> \
    ::push_back<at<(I) + 2>(S)>::push_back<at<(I) + 3>(S)> \
    ::push_back<at<(I) + 4>(S)>::push_back<at<(I) + 5>(S)> \
    ::push_back<at<(I) + 6>(S)>::push_back<at<(I) + 7>(S)>

#define PUSH_BACK_32(S, I) \
        PUSH_BACK_8(S, (I) + 0) PUSH_BACK_8(S, (I) + 8) \
        PUSH_BACK_8(S, (I) + 16) PUSH_BACK_8(S, (I) + 24)

#define PUSH_BACK_128(S, I) \
    PUSH_BACK_32(S, (I) + 0) PUSH_BACK_32(S, (I) + 32) \
    PUSH_BACK_32(S, (I) + 64) PUSH_BACK_32(S, (I) + 96)

// Macro to create char_sequence from c-string (limited to 128 chars) without leading '\0'
#define MAKE_CHAR_SEQUENCE(S) \
    strip_sequence<char_sequence<> \
    PUSH_BACK_128(S, 0) \
    ::push_back<check_size<128>(S) ? '\0' : '\0'> \
    >::type

// Macro to return an static std::string
#define STATIC_STRING(S) static_string<MAKE_CHAR_SEQUENCE(S)>::str

在线示例

这篇关于文字中的静态std :: string对象的宏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆