どんなコンピューで複数のC++の文字列にかかってしまいます。
-
20-08-2019 - |
質問
C#には、構文の特徴できるコンピ多くのデータの種類と1路線です。
string s = new String();
s += "Hello world, " + myInt + niceToSeeYouString;
s += someChar1 + interestingDecimal + someChar2;
池尾:そういうふうに考えている同等のC++?調査を実施しているのは、同じに見いだ特別ラインでをサポートしていない複数の文字列/変数の+演算子です。ここでもOKですが、どんなとしての快適性は十分満足できます
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();
マナーファームのStringフォーマッタrel="noreferrer"> 週ハーブサッターからの物品のこの教祖を見てみましょうの 他のヒント
5年後には誰も言及していない.append
?
#include <string>
std::string s;
s.append("Hello world, ");
s.append("nice to see you, ");
s.append("or not.");
s += "Hello world, " + "nice to see you, " + "or not.";
これらの文字列リテラルは、C ++のstd ::文字列ではありません - あなたがそれらを変換するために定義さます:
s += string("Hello world, ") + string("nice to see you, ") + string("or not.");
int型(またはその他のストリーミング型)を変換するには、あなたがブーストのlexical_castを使用するか、または独自の機能を提供することができます:
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."
...しかし、私はそれはあなたが探しているものだ疑い。あなたのケースでは、おそらくストリームを探しています:
std::stringstream ss;
ss << "Hello world, " << 42 << "nice to see you.";
std::string s = ss.str();
<時間>
文字列リテラルでしか動作:1 "の のように記述することができます"。連結は、コンパイラによって行われます。
のコードが容易になるstd::to_string
C ++ 14個のユーザ定義リテラルを使用し、
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;
文字列リテラルを連結コンパイル時に行うことができることに注意してください。ただ、削除+
。
str += "Hello World, " "nice to see you, " "or not";
より1ラインっぽいなソリューションを提供するには、次の機能をconcat
の単一の文に「クラシック」にstringstreamベースのソリューションを削減するために実装することができます。の。
これは、可変引数テンプレートや完璧な転送に基づいています。
の使用方法:の
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
の 実際の問題 た列の文字列リテラルと +
失敗したC++:
string s;
s += "Hello world, " + "nice to see you, " + "or not.";
上記のコード生成時にエラーが発生する。
C++(C)、連結のリテラル文字列だけを毎:
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.";
この意味があれば、コードを生成します。マクロ:
#define TRACE(arg) cout << #arg ":" << (arg) << endl;
...簡単なマクロで使用できるようなこ
int a = 5;
TRACE(a)
a += 7;
TRACE(a)
TRACE(a+7)
TRACE(17*11)
(ライブデモ...)
やば、 +
のための文字列リテラルとして既に提案する underscore_d):
string s = string("Hello world, ")+"nice to see you, "+"or not.";
他の溶液を組み合わせた文字列および const char*
各連結したステップ
string s;
s += "Hello world, "
s += "nice to see you, "
s += "or not.";
auto s = string("one").append("two").append("three")
の {fmt}図書館 ことができるの?
auto s = fmt::format("{}{}{}", "Hello world, ", myInt, niceToSeeYouString);
サブセットの図書館が提案した標準化として P0645テキストのフォーマット 場合には、上記のとなる:
auto s = std::format("{}{}{}", "Hello world, ", myInt, niceToSeeYouString);
免責事項:私の著書であるの{fmt}図書館があります。
あなたは(+演算子を定義する必要があります)すべてのデータのためにあなたが文字列にconcenateしたい入力し、まだオペレータは<<、ほとんどのタイプのために定義されているので、あなたはSTD ::にstringstreamを使用する必要があります。
くそー、50秒で倒す...
+=
を書き出す場合は、は、それはC#とほぼ同じように見えます。
string s("Some initial data. "); int i = 5;
s = s + "Hello world, " + "nice to see you, " + to_string(i) + "\n";
、OPコードの主な問題は、オペレータが+
const char *
連結しないことです。それはしかし、std::string
で動作します。
ここではC ++ 11件のラムダとfor_each
を使用し、separator
文字列を分離することを提供することを可能にする別の解決策です
#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);
少なくとも私のコンピュータ上の簡単なテストの後、(直線的に)うまくスケールのようです。ここで私が書いた簡単なテストがあります:
#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
たぶん、あなたは本当に1行でそれを行うには、私の「ストリーマー」ソリューションが好き
#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
使用して喜んでいる場合は、あなたはユーザ定義の文字列リテラルを利用することができます>とstd::string
オブジェクトと他のオブジェクトのためのプラス演算子をオーバーロード2つの関数テンプレートを定義します。唯一の落とし穴は、そうでない場合は、コンパイラが使用する演算子を知らない、std::enable_if
のプラス演算子をオーバーロードすることはありません。あなたは<のhref =」からテンプレート type_traits
するを使用してこれを行うことができますhttp://en.cppreference.com/w/cpp/header/type_traits」のrel = "nofollowを"> <=> を。文字列は、単に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
あなたはこれらの文字列を持っているしたいすべてのすべての場所で、このヘッダファイルをインクルードします。
#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
あなたはまた(、等...、<<、&)文字列クラスを "拡張" とお好みのオペレータを選択することができます
ここでは、コード使用オペレータは<<ストリームとの競合がない示すことである
注:あなたのコメントを外しs1.reserve(30)場合には、唯一の3つの新しい()オペレーター要求(;あなたは、残念ながら、コンストラクタ時に予約することができないS1 1、S2のための1、準備のための1)があります。準備金なしで、s1はそれが大きくなるにつれて、より多くのメモリを要求することがあるので、それはあなたのコンパイラの実装に依存する係数を育てる(鉱山があるように思わ1.5、5()この例では呼び出して新しい)
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;
}
このような何かが私のために動作します。
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);
上記の解決策に基づき、私は人生を容易にする私のプロジェクトのクラスvar_stringを作りました。例:
var_string x("abc %d %s", 123, "def");
std::string y = (std::string)x;
const char *z = x.c_str();
クラス自体ます:
#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;
}
このあなたはこのような関数呼び出しを作成することができます:
printMessage("message number : " + std::to_string(id));
印刷されます:メッセージ番号:10
このライナー液
#include <iostream>
#include <string>
int main() {
std::string s = std::string("Hi") + " there" + " friends";
std::cout << s << std::endl;
std::string r = std::string("Magic number: ") + std::to_string(13) + "!";
std::cout << r << std::endl;
return 0;
}
ですが少し突っついてき猫取得可能です。
また鋳造最初の引数に std::string
を用いて(左から右)で評価順 operator+
いることを確認するために 左 オペランドは常に std::string
.このように連結の std::string
左側の const char *
被演算子の右に戻他 std::string
, プの効果.
注意:がいくつかのオプションの右側の被演算子を含む const char *
, std::string
, は、 char
.
ですか否かを決定するには、マジック番号は13日または6227020800.
ラムダ関数を使用して簡単なpreproccessorマクロとにstringstreamは良い方法だと思われます:
#include <sstream>
#define make_string(args) []{std::stringstream ss; ss << args; return ss;}()
し、
auto str = make_string("hello" << " there" << 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
あなたは+ =を避けるためにしようとしたことがありますか? 代わりにVAR = VARの+を使用して... それは私のために働いています。
#include <iostream.h> // for string
string myName = "";
int _age = 30;
myName = myName + "Vincent" + "Thorpe" + 30 + " " + 2019;