c++ 如何声明constexpr C字符串?

0yycz8jy  于 2023-05-30  发布在  其他
关注(0)|答案(3)|浏览(188)

我想我很理解如何将关键字constexpr用于简单的变量类型,但当涉及到指向值的指针时,我感到困惑。
我想声明一个constexpr C字符串字面量,其行为如下

#define my_str "hello"

这意味着编译器将C字符串文字插入到我输入这个符号的每个地方,并且我将能够在编译时使用sizeof获得其长度。
constexpr char * const my_str = "hello";
const char * constexpr my_str = "hello";
constexpr char my_str [] = "hello";
还是别的什么

9ceoxa92

9ceoxa921#

constexpr char * const my_str = "hello";
不能,因为字符串文字不能转换为指向char* 的 * 指针。(它曾经在C++11之前,但即使在那时,转换也被弃用)。
const char * constexpr my_str = "hello";
不,constexpr不能去那里。
这将是良好的形式:

constexpr const char * my_str = "hello";

但它并不能满足这一点:
这样我就可以在编译时用sizeof等得到它的长度
constexpr char my_str [] = "hello";
这是格式良好的,您确实可以在编译时使用sizeof获得长度。注意,这个大小是数组的大小,而不是字符串的长度。该大小包括空终止符。

c0vxltue

c0vxltue2#

C++17中,可以使用std::string_viewstring_view_literals

using namespace std::string_view_literals;
constexpr std::string_view my_str = "hello, world"sv;

然后
my_str.size()是编译时间常数。

fgw7neuy

fgw7neuy3#

C++11

由于constexpr const char*字符串字面量的空终止,您可以简单地使用std::strlen,如果它应该在编译时工作,则可以轻松定义自定义函数:

constexpr std::size_t _strlen(char const* s, std::size_t count = 0) {
    return (*s == '\0') ? count : _strlen(s + 1, count + 1);
}

(C++11 constexpr函数只能包含exactly one return statement,所以使用递归。
如果sizeof必须 * 另外 * 像在数组上一样工作(即包含了null-termination),你可以使用variadic templates来定义字符串字面量,如下所示:

constexpr std::size_t _strlen(char const* s, std::size_t count = 0) {
    return (*s == '\0') ? count : _strlen(s + 1, count + 1);
}

// Parameter pack helpers (similar to C++14)
template<std::size_t ...> struct _index_sequence { using type = _index_sequence; };
template<std::size_t N, std::size_t ... S> struct gen_pack_sequence: gen_pack_sequence<N - 1, N - 1, S...> {};
template<std::size_t ... S> struct gen_pack_sequence<0, S...> : _index_sequence<S...> {};
template<std::size_t N> using _make_index_sequence = typename gen_pack_sequence<N>::type;

template<char ... Chars> struct char_sequence {
    static constexpr char value[] = { Chars... };
    template<template<char...> class Template> using param_pack = Template<Chars...>;
};
template<char ... Chars> constexpr char char_sequence<Chars...>::value[];
template<char ... Chars> struct char_string: char_sequence<Chars..., '\0'> {};

// Compile-time string literals ; Concept: https://ideone.com/QvXuYf
template<typename S, typename T> struct _struct_to_string;
template<typename S, std::size_t ... Indices> struct _struct_to_string<S, _index_sequence<Indices...>> { typedef char_string<S::get()[Indices] ...> type; };
template<typename S> struct struct_to_string { typedef _make_index_sequence<_strlen(S::get())> indices; typedef typename _struct_to_string<S, indices>::type type; };
#define CONSTEXPR_STRING(name, s) \
    struct name ## __struct { constexpr static const char* get() { return s; } }; \
    typedef struct_to_string<name ## __struct>::type name

使用output

CONSTEXPR_STRING(var, "Hello!");

constexpr const char* _var = var::value;
constexpr std::size_t _varlen = _strlen(_var);

int main()
{
    std::cout << _var << std::endl; // "Hello!" has length 6
    std::cout << _varlen << std::endl; // 6
    std::cout << _strlen(_var) << std::endl; // 6
    std::cout << std::strlen(_var) << std::endl; // 6
    std::cout << sizeof(var::value) << std::endl; // 7: size of { 'H', 'e', 'l', 'l', 'o', '!', '\0' }
    std::cout << sizeof(_var) << std::endl; // 8: a pointer is 64 bits = 8 bytes
}

这可能看起来有点过分,因为可以简单地使用一个数组,如

constexpr char _var[] = "hello";

但是char_string类型可以被扩展以支持所有可能的constexpr字符串特征,并且通过使用::param_pack是特别灵活的,这在例如w.r.t.编译时string concatenation

相关问题