在C ++中,字符串文字的类型为const char [N]
,其中N
为std::size_t
,是字符数加1(零字节终止符)。它们驻留在静态存储中,可从程序初始化到终止。
通常,采用常量字符串的函数不需要std::basic_string
的接口,或者更愿意避免动态分配;例如,它们可能只需要字符串本身及其长度。 std::basic_string
,尤其必须提供一种从语言的本地字符串文字构建的方法。这些函数提供了一个采用C风格字符串的变体:
void function_that_takes_a_constant_string ( const char * /*const*/ s );
// Array-to-pointer decay happens, and takes away the string's length
function_that_takes_a_constant_string( "Hello, World!" );
如this answer中所述,数组衰减为指针,但它们的尺寸被删除了。在字符串文字的情况下,这意味着它们的长度(在编译时已知)将丢失,必须通过迭代指向的内存直到找到零字节来重新计算在运行时。这不是最佳的。
但是,字符串文字以及通常的数组可以使用模板参数推导作为引用传递,以保持其大小:
template<std::size_t N>
void function_that_takes_a_constant_string ( const char (& s)[N] );
// Transparent, and the string's length is kept
function_that_takes_a_constant_string( "Hello, World!" );
模板函数可以作为另一个函数的代理,即真正的函数,它将获取指向字符串及其长度的指针,以避免代码暴露并保持长度。
// Calling the wrapped function directly would be cumbersome.
// This wrapper is transparent and preserves the string's length.
template<std::size_t N> inline auto
function_that_takes_a_constant_string
( const char (& s)[N] )
{
// `s` decays to a pointer
// `N-1` is the length of the string
return function_that_takes_a_constant_string_private_impl( s , N-1 );
}
// Isn't everyone happy now?
function_that_takes_a_constant_string( "Hello, World!" );
为什么不能更广泛地使用它?特别是,为什么std::basic_string
没有具有建议签名的构造函数?
注意:我不知道如何命名建议的参数;如果您知道如何,请提出问题标题的版本。
答案 0 :(得分:3)
添加这样的模板化重载的麻烦很简单:
只要使用char
类型的静态缓冲区调用函数,它就会被使用,即使缓冲区不是整个一个字符串,你真的想通过只有初始字符串(嵌入的零比终止零更不常见,使用部分缓冲区非常常见):当前代码很少包含从数组到指针的显式衰减第一个元素,使用强制转换或函数调用。
演示代码(On coliru):
#include <stdio.h>
#include <string.h>
auto f(const char* s, size_t n) {
printf("char* size_t %u\n", (unsigned)n);
(void)s;
}
auto f(const char* s) {
printf("char*\n");
return f(s, strlen(s));
}
template<size_t N> inline auto
f( const char (& s)[N] ) {
printf("char[&u]\n");
return f(s, N-1);
}
int main() {
char buffer[] = "Hello World";
f(buffer);
f(+buffer);
buffer[5] = 0;
f(buffer);
f(+buffer);
}
请记住:如果你在C中谈论一个字符串,它总是表示一个以0结尾的字符串,而在C ++中它也可以表示一个std::string
,它被计算在内。
答案 1 :(得分:3)
char buf[MAX_LEN];
由于这通常 它们如何被使用,因此似乎不必要甚至冒险来添加新的basic_string
构造函数const CharT (&)[N]
的模板。
尽管如此,整个事情仍然非常临界。
答案 2 :(得分:3)
我相信这是基于用户定义的字符串文字
在C ++ 14中解决的http://en.cppreference.com/w/cpp/string/basic_string/operator%22%22s
#include <string>
int main()
{
//no need to write 'using namespace std::literals::string_literals'
using namespace std::string_literals;
std::string s2 = "abc\0\0def"; // forms the string "abc"
std::string s1 = "abc\0\0def"s; // form the string "abc\0\0def"
}
答案 3 :(得分:0)
你可以创建一个帮助类来修复它,而不必为每个函数使用重载
struct string_view
{
const char* ptr;
size_t size;
template<size_t N>
string_view(const char (&s)[N])
{
ptr = s;
size = N;
}
string_view(const std::string& s)
{
ptr = s.data();
size = s.size() + 1; // for '\0' at end
}
};
void f(string_view);
main()
{
string_view s { "Hello world!" };
f("test");
}
您应该扩展此类以获取辅助函数(例如begine
和end
),以简化程序中的使用。