如何在一行上连接多个C ++string?
C#有一个语法function,您可以在一行上连接多个数据types。
string s = new String(); s += "Hello world, " + myInt + niceToSeeYouString; s += someChar1 + interestingDecimal + someChar2;
C ++中的等价物是什么? 据我所知,你必须在不同的行上完成,因为它不支持+运算符的多个string/variables。 这是好的,但看起来不整齐。
string s; s += "Hello world, " + "nice to see you, " + "or not.";
上面的代码产生一个错误。
#include <sstream> #include <string> std::stringstream ss; ss << "Hello, world, " << myInt << niceToSeeYouString; std::string s = ss.str();
看一下这个来自Herb Sutter的文章: 庄园农场的string格式
s += "Hello world, " + "nice to see you, " + "or not.";
那些字符数组文字不是C ++ std :: strings – 你需要转换它们:
s += string("Hello world, ") + string("nice to see you, ") + string("or not.");
要转换整数(或任何其他streamertypes),您可以使用一个提升lexical_cast或提供自己的function:
template <typename T> string Str( const T & t ) { ostringstream os; os << t; return os.str(); }
你现在可以这样说:
string s = "The meaning is " + Str( 42 );
你的代码可以写成1 ,
s = "Hello world," "nice to see you," "or not."
…但我怀疑这就是你要找的。 在你的情况下,你可能正在寻找stream:
std::stringstream ss; ss << "Hello world, " << 42 << "nice to see you."; std::string s = ss.str();
1 “ 可以写成 ”:这只适用于string文字。 串联由编译器完成。
5年来没有人提到过。
#include <string> std::string s; s.append("Hello world, "); s.append("nice to see you, "); s.append("or not.");
使用C ++ 14用户定义的文字和std::to_string
代码变得更容易。
using namespace std::literals::string_literals; std::string str; str += "Hello World, "s + "nice to see you, "s + "or not"s; str += "Hello World, "s + std::to_string(my_int) + other_string;
请注意,连接string文字可以在编译时完成。 只要删除+
。
str += "Hello World, " "nice to see you, " "or not";
为了提供更为单线的解决scheme:可以实现函数concat
以将“经典的”基于stringstream的解决scheme简化为单个语句 。 它基于可变的模板和完美的转发。
用法:
std::string s = concat(someObject, " Hello, ", 42, " I concatenate", anyStreamableType);
执行:
void addToStream(std::ostringstream&) { } template<typename T, typename... Args> void addToStream(std::ostringstream& a_stream, T&& a_value, Args&&... a_args) { a_stream << std::forward<T>(a_value); addToStream(a_stream, std::forward<Args>(a_args)...); } template<typename... Args> std::string concat(Args&&... a_args) { std::ostringstream s; addToStream(s, std::forward<Args>(a_args)...); return s.str(); }
提高::格式
或std :: stringstream
std::stringstream msg; msg << "Hello world, " << myInt << niceToSeeYouString; msg.str(); // returns std::string object
你将不得不为每个数据types定义一个operator +(),这个数据types可以包含在string中,但是由于operator <<是为大多数types定义的,所以你应该使用std :: stringstream。
该死,50秒…
如果你写出+=
,它看起来几乎和C#一样
string s("Some initial data. "); int i = 5; s = s + "Hello world, " + "nice to see you, " + to_string(i) + "\n";
也许你喜欢我的“stream光”解决scheme真正在一行:
#include <iostream> #include <sstream> using namespace std; class Streamer // class for one line string generation { public: Streamer& clear() // clear content { ss.str(""); // set to empty string ss.clear(); // clear error flags return *this; } template <typename T> friend Streamer& operator<<(Streamer& streamer,T str); // add to streamer string str() // get current string { return ss.str();} private: stringstream ss; }; template <typename T> Streamer& operator<<(Streamer& streamer,T str) { streamer.ss<<str;return streamer;} Streamer streamer; // make this a global variable class MyTestClass // just a test class { public: MyTestClass() : data(0.12345){} friend ostream& operator<<(ostream& os,const MyTestClass& myClass); private: double data; }; ostream& operator<<(ostream& os,const MyTestClass& myClass) // print test class { return os<<myClass.data;} int main() { int i=0; string s1=(streamer.clear()<<"foo"<<"bar"<<"test").str(); // test strings string s2=(streamer.clear()<<"i:"<<i++<<" "<<i++<<" "<<i++<<" "<<0.666).str(); // test numbers string s3=(streamer.clear()<<"test class:"<<MyTestClass()).str(); // test with test class cout<<"s1: '"<<s1<<"'"<<endl; cout<<"s2: '"<<s2<<"'"<<endl; cout<<"s3: '"<<s3<<"'"<<endl; }
你可以在这方面使用这个头文件: https : //github.com/theypsilon/concat
using namespace concat; assert(concat(1,2,3,4,5) == "12345");
在引擎盖下,你将使用一个std :: ostringstream。
如果您愿意使用c++11
,则可以使用用户定义的string文字,并定义两个函数模板,将std::string
对象和其他对象的加号运算符重载。 唯一的错误是不要重载std::string
的加号运算符,否则编译器不知道要使用哪个运算符。 你可以通过使用type_traits
的模板std::enable_if
来完成。 之后,string的行为就像在Java或C#中。 详情请参阅我的示例实现。
主要代码
#include <iostream> #include "c_sharp_strings.hpp" using namespace std; int main() { int i = 0; float f = 0.4; double d = 1.3e-2; string s; s += "Hello world, "_ + "nice to see you. "_ + i + " "_ + 47 + " "_ + f + ',' + d; cout << s << endl; return 0; }
文件c_sharp_strings.hpp
将这个头文件包含在你想要这些string的所有地方。
#ifndef C_SHARP_STRING_H_INCLUDED #define C_SHARP_STRING_H_INCLUDED #include <type_traits> #include <string> inline std::string operator "" _(const char a[], long unsigned int i) { return std::string(a); } template<typename T> inline typename std::enable_if<!std::is_same<std::string, T>::value && !std::is_same<char, T>::value && !std::is_same<const char*, T>::value, std::string>::type operator+ (std::string s, T i) { return s + std::to_string(i); } template<typename T> inline typename std::enable_if<!std::is_same<std::string, T>::value && !std::is_same<char, T>::value && !std::is_same<const char*, T>::value, std::string>::type operator+ (T i, std::string s) { return std::to_string(i) + s; } #endif // C_SHARP_STRING_H_INCLUDED
正如其他人所说,OP代码的主要问题是运算符+
不连接const char *
; 它适用于std::string
,但是。
这是另一个使用C ++ 11 lambda和for_each
解决scheme,它允许提供一个separator
来分隔string:
#include <vector> #include <algorithm> #include <iterator> #include <sstream> string join(const string& separator, const vector<string>& strings) { if (strings.empty()) return ""; if (strings.size() == 1) return strings[0]; stringstream ss; ss << strings[0]; auto aggregate = [&ss, &separator](const string& s) { ss << separator << s; }; for_each(begin(strings) + 1, end(strings), aggregate); return ss.str(); }
用法:
std::vector<std::string> strings { "a", "b", "c" }; std::string joinedStrings = join(", ", strings);
至less在我的电脑上进行了一次快速testing之后,它似乎可以很好地扩展(线性) 这是我写的一个快速testing:
#include <vector> #include <algorithm> #include <iostream> #include <iterator> #include <sstream> #include <chrono> using namespace std; string join(const string& separator, const vector<string>& strings) { if (strings.empty()) return ""; if (strings.size() == 1) return strings[0]; stringstream ss; ss << strings[0]; auto aggregate = [&ss, &separator](const string& s) { ss << separator << s; }; for_each(begin(strings) + 1, end(strings), aggregate); return ss.str(); } int main() { const int reps = 1000; const string sep = ", "; auto generator = [](){return "abcde";}; vector<string> strings10(10); generate(begin(strings10), end(strings10), generator); vector<string> strings100(100); generate(begin(strings100), end(strings100), generator); vector<string> strings1000(1000); generate(begin(strings1000), end(strings1000), generator); vector<string> strings10000(10000); generate(begin(strings10000), end(strings10000), generator); auto t1 = chrono::system_clock::now(); for(int i = 0; i<reps; ++i) { join(sep, strings10); } auto t2 = chrono::system_clock::now(); for(int i = 0; i<reps; ++i) { join(sep, strings100); } auto t3 = chrono::system_clock::now(); for(int i = 0; i<reps; ++i) { join(sep, strings1000); } auto t4 = chrono::system_clock::now(); for(int i = 0; i<reps; ++i) { join(sep, strings10000); } auto t5 = chrono::system_clock::now(); auto d1 = chrono::duration_cast<chrono::milliseconds>(t2 - t1); auto d2 = chrono::duration_cast<chrono::milliseconds>(t3 - t2); auto d3 = chrono::duration_cast<chrono::milliseconds>(t4 - t3); auto d4 = chrono::duration_cast<chrono::milliseconds>(t5 - t4); cout << "join(10) : " << d1.count() << endl; cout << "join(100) : " << d2.count() << endl; cout << "join(1000) : " << d3.count() << endl; cout << "join(10000): " << d4.count() << endl; }
结果(毫秒):
join(10) : 2 join(100) : 10 join(1000) : 91 join(10000): 898
你也可以“扩展”string类并select你喜欢的操作符(<<,&,|等等)
这里是使用operator <<的代码来显示与stream没有冲突
注意:如果取消注释s1.reserve(30),只有3个新的()操作符请求(s1为1,s2为1,保留为1;不幸的是,在构造函数时不能保留)。 没有保留,s1不得不随着它的增长请求更多的内存,所以它取决于你的编译器实现的增长因子(在这个例子中我的看起来是1.5,5个new()调用)
namespace perso { class string:public std::string { public: string(): std::string(){} template<typename T> string(const T v): std::string(v) {} template<typename T> string& operator<<(const T s){ *this+=s; return *this; } }; } using namespace std; int main() { using string = perso::string; string s1, s2="she"; //s1.reserve(30); s1 << "no " << "sunshine when " << s2 << '\'' << 's' << " gone"; cout << "Aint't "<< s1 << " ..." << endl; return 0; }
实际的问题是在C ++中串联string+
失败:
string s;
s += "Hello world, " + "nice to see you, " + "or not.";
上面的代码产生一个错误。
在C ++中(也在C中),通过将它们放在右边并紧接来连接string文字:
string s0 = "Hello world, " "nice to see you, " "or not."; string s1 = "Hello world, " /*same*/ "nice to see you, " /*result*/ "or not."; string s2 = "Hello world, " /*line breaks in source code as well as*/ "nice to see you, " /*comments don't matter*/ "or not.";
这是有道理的,如果你在macros中生成代码:
#define TRACE(arg) cout << #arg ":" << (arg) << endl;
一个简单的macros,可以像这样使用
int a = 5; TRACE(a) a += 7; TRACE(a) TRACE(a+7) TRACE(17*11)
( 现场演示… )
或者,如果你坚持使用+
作为string文字(正如underscore_d所build议的那样):
string s = string("Hello world, ")+"nice to see you, "+"or not.";
另一个解决scheme将string和const char*
为每个级联步骤
string s; s += "Hello world, " s += "nice to see you, " s += "or not.";
auto s = string("one").append("two").append("three")
像这样的东西适合我
namespace detail { void concat_impl(std::ostream&) { /* do nothing */ } template<typename T, typename ...Args> void concat_impl(std::ostream& os, const T& t, Args&&... args) { os << t; concat_impl(os, std::forward<Args>(args)...); } } /* namespace detail */ template<typename ...Args> std::string concat(Args&&... args) { std::ostringstream os; detail::concat_impl(os, std::forward<Args>(args)...); return os.str(); } // ... std::string s{"Hello World, "}; s = concat(s, myInt, niceToSeeYouString, myChar, myFoo);
基于上述解决scheme,我为我的项目做了一个类var_string,使生活变得简单。 例子:
var_string x("abc %d %s", 123, "def"); std::string y = (std::string)x; const char *z = x.c_str();
class级本身:
#include <stdlib.h> #include <stdarg.h> class var_string { public: var_string(const char *cmd, ...) { va_list args; va_start(args, cmd); vsnprintf(buffer, sizeof(buffer) - 1, cmd, args); } ~var_string() {} operator std::string() { return std::string(buffer); } operator char*() { return buffer; } const char *c_str() { return buffer; } int system() { return ::system(buffer); } private: char buffer[4096]; };
仍然想知道是否会有更好的C ++?
在c11:
void printMessage(std::string&& message) { std::cout << message << std::endl; return message; }
这允许你创build这样的函数调用:
printMessage("message number : " + std::to_string(id));
将打印:消息号码:10
这适用于我:
#include <iostream> using namespace std; #define CONCAT2(a,b) string(a)+string(b) #define CONCAT3(a,b,c) string(a)+string(b)+string(c) #define CONCAT4(a,b,c,d) string(a)+string(b)+string(c)+string(d) #define HOMEDIR "c:\\example" int main() { const char* filename = "myfile"; string path = CONCAT4(HOMEDIR,"\\",filename,".txt"); cout << path; return 0; }
输出:
c:\example\myfile.txt