方便地在C ++中声明编译时字符串 [英] Conveniently Declaring Compile-Time Strings in C++

查看:119
本文介绍了方便地在C ++中声明编译时字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

能够在C ++编译期创建和操作字符串有几个有用的应用程序。虽然可以在C ++中创建编译时字符串,但是该过程非常繁琐,因为字符串需要声明为一个可变的字符序列,例如



<$ p $使用str = sequence<'H','e','l','l','o',',','w','o','r' l','d','!'> ;;

字符串连接,子字符串提取等操作可以轻松地实现为序列操作的字符。 是否可以更方便地声明编译时字符串?



为什么现有的方法失败



理想情况下,我们希望能够如下声明编译时字符串:

  //方法1 
使用str1 = sequence<Hello,world!> ;;

或使用用户定义的文字,

  //方法2 
constexpr auto str2 =Hello,world!

其中 decltype(str2) constexpr 构造函数。使用方法1的混乱版本是可能实现的,利用这样的事实,你可以做以下事情:

  template< unsigned Size,const char Array [Size]> 
struct foo;

但是,数组需要有外部链接,所以要使方法1工作,必须写如下:

  / *这里执行数组排序。 * / 

constexpr const char str [] =Hello,world!

int main()
{
使用s = string< 13,str> ;;
return 0;
}

不用说,这很不方便。方法2实际上是不可能实现的。如果我们要声明一个( constexpr )文字运算符,那么我们如何指定返回类型呢?因为我们需要运算符返回一个可变的字符序列,所以我们需要使用 const char * 参数来指定返回类型:

  constexpr auto 
operator_s(const char * s,size_t n) - > / *一些使用`s'的元函数* /

这会导致编译错误,因为 s 不是 constexpr 。尝试通过执行以下操作不会有什么帮助。

 模板< char ... Ts> 
constexpr sequence< Ts ...>运算符_s(){return {}; }

标准规定此特定的运算符格式保留用于整数和浮点类型。 123_s 可以工作, abc_s 不会。如果我们完全抛弃用户定义的文本,并且只使用一个常规的 constexpr 函数?

 code> template< unsigned Size> 
constexpr auto
string(const char(& array)[Size]) - > / *一些使用`array`的元函数* /

,现在 constexpr 函数的参数本身不再是 constexpr 类型。



我相信应该可以定义一个C预处理器宏,它接受一个字符串和字符串的大小作为参数,并返回一个由字符串中的字符组成的序列(使用 BOOST_PP_FOR ,字符串化,数组下标等)。但是,我没有时间(或足够的兴趣)来实现这样的宏=)

解决方案

任何符合 Scott Schurr的 str_const C ++ Now 2012 上发布。它需要 constexpr



以下是如何使用它,以及它可以做什么:

  int 
main()
{
constexpr str_const my_string =Hello,world!
static_assert(my_string.size()== 13,);
static_assert(my_string [4] =='o',);
constexpr str_const my_other_string = my_string;
static_assert(my_string == my_other_string,);
constexpr str_const world(my_string,7,5);
static_assert(world ==world,);
// constexpr char x = world [5]; //不编译,因为索引超出范围!
}

它比编译时范围检查要冷得多! p>

使用和实现都没有宏。并且没有对字符串大小的人为限制。我会在这里发布实现,但我尊重斯科特的隐含版权。实施是在他的演示文稿的单一幻灯片链接到上面。


Being able to create and manipulate strings during compile-time in C++ has several useful applications. Although it is possible to create compile-time strings in C++, the process is very cumbersome, as the string needs to be declared as a variadic sequence of characters, e.g.

using str = sequence<'H', 'e', 'l', 'l', 'o', ', ', 'w', 'o', 'r', 'l', 'd', '!'>;

Operations such as string concatenation, substring extraction, and many others, can easily be implemented as operations on sequences of characters. Is it possible to declare compile-time strings more conveniently? If not, is there a proposal in the works that would allow for convenient declaration of compile-time strings?

Why Existing Approaches Fail

Ideally, we would like to be able to declare compile-time strings as follows:

// Approach 1
using str1 = sequence<"Hello, world!">;

or, using user-defined literals,

// Approach 2
constexpr auto str2 = "Hello, world!"_s;

where decltype(str2) would have a constexpr constructor. A messier version of approach 1 is possible to implement, taking advantage of the fact that you can do the following:

template <unsigned Size, const char Array[Size]>
struct foo;

However, the array would need to have external linkage, so to get approach 1 to work, we would have to write something like this:

/* Implementation of array to sequence goes here. */

constexpr const char str[] = "Hello, world!";

int main()
{
    using s = string<13, str>;
    return 0;
}

Needless to say, this is very inconvenient. Approach 2 is actually not possible to implement. If we were to declare a (constexpr) literal operator, then how would we specify the return type? Since we need the operator to return a variadic sequence of characters, so we would need to use the const char* parameter to specify the return type:

constexpr auto
operator"" _s(const char* s, size_t n) -> /* Some metafunction using `s` */

This results in a compile error, because s is not a constexpr. Trying to work around this by doing the following does not help much.

template <char... Ts>
constexpr sequence<Ts...> operator"" _s() { return {}; }

The standard dictates that this specific literal operator form is reserved for integer and floating-point types. While 123_s would work, abc_s would not. What if we ditch user-defined literals altogether, and just use a regular constexpr function?

template <unsigned Size>
constexpr auto
string(const char (&array)[Size]) -> /* Some metafunction using `array` */

As before, we run into the problem that the array, now a parameter to the constexpr function, is itself no longer a constexpr type.

I believe it should be possible to define a C preprocessor macro that takes a string and the size of the string as arguments, and returns a sequence consisting of the characters in the string (using BOOST_PP_FOR, stringification, array subscripts, and the like). However, I do not have the time (or enough interest) to implement such a macro =)

解决方案

I haven't seen anything to match the elegance of Scott Schurr's str_const presented at C++ Now 2012. It does require constexpr though.

Here's how you can use it, and what it can do:

int
main()
{
    constexpr str_const my_string = "Hello, world!";
    static_assert(my_string.size() == 13, "");
    static_assert(my_string[4] == 'o', "");
    constexpr str_const my_other_string = my_string;
    static_assert(my_string == my_other_string, "");
    constexpr str_const world(my_string, 7, 5);
    static_assert(world == "world", "");
//  constexpr char x = world[5]; // Does not compile because index is out of range!
}

It doesn't get much cooler than compile-time range checking!

Both the use, and the implementation, is free of macros. And there is no artificial limit on string size. I'd post the implementation here, but I'm respecting Scott's implicit copyright. The implementation is on a single slide of his presentation linked to above.

这篇关于方便地在C ++中声明编译时字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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