如何在一行上连接多个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