连接字符串族
Concatenate a family of string
我想编写一个函数,将任何std::string
序列与幕后只有一个malloc连接起来。因此,需要首先计算字符串的总长度。该函数需要以这种方式使用:
std::string s0 = ...;
std::string s1 = ...;
std::string s2 = ...;
std::string s = join(s0, s1, s2);
更好的join
是混合使用std::string
和std::string_view
。如果我们可以添加字符串文字,那就更好了。您将如何在 C++11 中编写这样的函数(它需要使用gcc 4.8.5
和Visual Studio 2015
进行编译(?
如果你有一个string_view
类型,那么你可以接受一个string_view
集合,对它们的大小求和,分配,然后复制。
std::string join(std::initializer_list<string_view> values)
{
std::string result;
result.reserve(std::accumulate(values.begin(), values.end(), 0, [](string_view s) { return s.length(); }));
std::for_each(values.begin(), values.end(), [&result](string_view s) { result.append(s.data()); });
return result;
}
使用 range-v3,您可以使用concat
:
const std::string s = ranges::view::concat(s0, s1, " worldn");
下面是一个可能的实现:
template<typename... Args>
std::string join(const Args&... args)
{
size_t size = 0;
for( const std::string& s : { args... } )
size += s.size();
std::string result;
result.reserve(size);
for( const std::string& s : { args... } )
result += s;
return result;
}
演示:https://wandbox.org/permlink/qwG0LMewsHwVuGXN
> Benoit 几乎拥有它,他的实现只需要必要的样板来处理不同的字符串类型。 值得称赞的是,我必须承认这是相当多的样板。:)
使用gcc -std=c++17
编译
#include <string>
#include <string.h>
#include <string_view>
#include <iostream>
namespace detail {
template<typename C>
size_t myStrLen(const std::basic_string<C>& s) { return s.length(); }
template<typename C>
size_t myStrLen(const std::basic_string_view<C>& s) { return s.length(); }
size_t myStrLen(char) { return 1; }
size_t myStrLen(wchar_t) { return 1; }
size_t myStrLen(const char* s) { return strlen(s); }
size_t myStrLen(const wchar_t* s) { return wcslen(s); }
template<typename T, typename...Args>
size_t myStrLen(T&& t, Args&&...args)
{
return myStrLen(std::forward<T>(t)) + myStrLen(args...);
}
template<typename C, typename T>
void myConcat(std::basic_string<C>& result, T&& t)
{
result += t;
}
template<typename C, typename T, typename...Args>
void myConcat(std::basic_string<C>& result, T&& t, Args&&...args)
{
result += t;
myConcat(result, args...);
}
}
template<typename C, typename... Args>
auto join(Args&&... args)
{
std::basic_string<C> result;
result.reserve(detail::myStrLen(args...));
detail::myConcat(result, args...);
return result;
}
template<typename... Args>
auto join(Args&&... args)
{
return join<char>(args...);
}
template<typename... Args>
auto wjoin(Args&&... args)
{
return join<wchar_t>(args...);
}
int main()
{
std::string str{"hello"};
std::string_view sv{"world"};
std::wstring wstr{L"hello"};
std::wstring_view wsv{L"world"};
std::cout << join(str, " ", sv, 'n');
std::wcout << wjoin(wstr, L" ", wsv, L'n');
return 0;
}
[编辑] 将模板join<charType>
移出命名空间详细信息,因为这可能对其他模板构造有用。
我相信使用完美的转发和可变参数模板参数是可能的。
joinStr.hpp :
class joinStr {
public:
template<typename... Args>
joinStr(const std::string& first, Args&&... args): ret(""), size(0) {
size = first.length();
getSize((args)...);
std::cout << "before reserve : " << ret.capacity() << std::endl;
ret.reserve(size);
std::cout << "after reserve : " << ret.capacity() << std::endl;
ret.append(first);
join(std::forward<Args>(args)...);
}
~joinStr() {}
std::string getStr() {
std::cout << ret << std::endl;
return ret;
}
private:
std::string ret;
int size;
int getSize() {
std::cout << "size : " << size << std::endl;
return size;
}
template<typename... Args>
int getSize(const std::string& first, const Args&... args) {
size += first.length();
return getSize((args)...);
}
template<typename... Args>
int getSize(char* first, const Args&... args) {
size += strlen(first);
return getSize((args)...);
}
template<typename... Args>
int getSize(const char* first, const Args&... args) {
size += strlen(first);
return getSize((args)...);
}
void join() {
std::cout << "Final capacity : " << ret.capacity() << std::endl;
}
template<typename... Args>
void join(const std::string& first, Args&&... args) {
ret.append(first);
join(std::forward<Args>(args)...);
}
template<typename... Args>
void join(char* first, Args&&... args) {
ret.append(first);
join(std::forward<Args>(args)...);
}
template<typename... Args>
void join(const char* first, Args&&... args) {
ret.append(first);
join(std::forward<Args>(args)...);
}
};
主要:
int main() {
std::string s1 = "hello";
std::string s2 = "world !";
std::string s3 = "meatpopsicle";
const char* s4 = "__yeah__";
joinStr c(s1, s2, s3, s4);
return 1;
}
请注意,我将其包装在类中,但您可以在类外执行相同的操作。
作为奖励,它适用于 std::string、const char* 和 char*。
编辑:修复了在getSize中重用移动值的问题,并在Caleth的建议后为常量字符*添加了模板
编辑 2: 允许在常量字符*之后传递size_t字段而不是使用 strlen 的版本。
class joinStr {
public:
template<typename... Args>
joinStr(const std::string& first, Args&&... args): ret(""), size(0) {
size = first.length();
getSize(args...);
std::cout << "before reserve : " << ret.capacity() << std::endl;
ret.reserve(size);
std::cout << "after reserve : " << ret.capacity() << std::endl;
ret.append(first);
join(std::forward<Args>(args)...);
}
~joinStr() {}
std::string getStr() {
std::cout << ret << std::endl;
return ret;
}
private:
std::string ret;
int size;
int getSize() {
std::cout << "size : " << size << std::endl;
return size;
}
template<typename... Args>
int getSize(const std::string& first, const Args&... args) {
size += first.length();
return getSize((args)...);
}
// const char *
template<typename... Args, typename T>
int getSize(const char* first, const T& t, const Args&... args) {
getSizeImpl<T>(first, t, std::integral_constant<bool, std::is_same<T, size_t>::value>());
return getSize(t, args...);
}
template<typename T>
void getSizeImpl(const char* first, const T& t, std::false_type) {
// Case when the next argument is not a size_t type
size += strlen(first);
}
template<typename T>
void getSizeImpl(const char* first,const T& t, std::true_type) {
// Do nothing
}
template<typename... Args>
int getSize(size_t s, const Args&... args) {
size += s;
std::cout << "size_t " << s << " in getSize" << std::endl;
return getSize(args...);
}
void join() {
std::cout << "Final capacity : " << ret.capacity() << std::endl;
}
template<typename... Args>
void join(const std::string& first, Args&&... args) {
ret.append(first);
join(std::forward<Args>(args)...);
}
template<typename... Args>
void join(char* first, Args&&... args) {
ret.append(first);
join(std::forward<Args>(args)...);
}
template<typename... Args>
void join(const char* first, Args&&... args) {
ret.append(first);
join(std::forward<Args>(args)...);
}
template<typename... Args>
void join(size_t s, Args&&... args) {
join(std::forward<Args>(args)...);
}
};
主要:
int main() {
std::string s1 = "hello";
std::string s2 = "world !";
std::string s3 = "meatpopsicle";
const char* s4 = "__yeah__";
joinStr c(s1, s2, s3, s4, (size_t)8);
return 1;
}
相关文章:
- 使用短运算符的字符串连接有区别吗?
- 字符串连接时间复杂度 c++
- 如何将两个 jlong 数据类型转换为 jstring,然后将两个字符串连接在一起以便从 JNI 将字符串返回给 jav
- 如何在 C 宏中将变量字符串与文字字符串连接起来?
- C++中干净高效的字符串连接
- 如何将 Unicode 字符串连接成字符串以传递到 mysql 调用中
- 如何与字符串连接thar数组
- 如何将平台^字符串转换为wstring,然后与L字符串连接
- 如何在c++中进行快速字符串连接
- 在C++中,相当于CPython字符串连接
- 如何在 c++ 中使用 STL 将带有空格的字符串连接成一个字符串
- C++将三个char*字符串连接在一起
- 尝试通过二叉树中的递归返回字符串(连接)
- 使用流的字符串连接返回垃圾
- 将字符串变量与整数和文本字符串连接起来的 C++ 字符串流
- 将 int 变量与字符串连接会导致奇怪的输出
- C++ 将常量字符 * 与字符串连接起来,仅打印常量字符 *
- 通过将模板参数与字符串连接起来生成C++类型名
- 将我的对象与字符串连接
- 没有得到预期的结果字符串连接