我想编写一个函数,将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
进行编译?)
答案 0 :(得分:4)
如果你有int
类型,那么你可以接受string_view
的集合,加上它们的大小,分配,然后复制。
string_view
答案 1 :(得分:3)
使用range-v3,您可以使用concat
:
const std::string s = ranges::view::concat(s0, s1, " world\n");
答案 2 :(得分:2)
这是一个可能的实现:
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;
}
答案 3 :(得分:2)
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>
移出命名空间详细信息,因为这对其他模板构造很有用。
答案 4 :(得分:1)
我相信可以使用完美转发和可变参数模板参数。
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's建议之后为const char *添加了模板
编辑2 : 允许在const char *之后传递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;
}