私のファイルの一番上に
#define AGE "42"
ファイルの後半で、IDを複数回使用します。
1 std::string name = "Obama";
2 std::string str = "Hello " + name + " you are " + AGE + " years old!";
3 str += "Do you feel " + AGE + " years old?";
エラーが表示されます:
「エラー:タイプ「const char [35]」および「const char [2]」の無効なオペランドはバイナリ「operator +」に」
3行目で調査しましたが、C++がさまざまな文字列をどのように処理していたのかがわかり、「AGE」を「string(AGE)」に変更することで修正できました。しかし、今日までインスタンスの1つを誤って見逃しており、「AGE」だけのインスタンスがまだあったのに、なぜコンパイラーが文句を言わないのか疑問に思っていました。
試行錯誤を繰り返して、関数本体で作成された別の文字列を連結しない行でstring(AGE)
のみが必要であることがわかりました。
私の質問は、「C++は、関数で定義した文字列も連結しない限り、プリプロセッサによってそこに置かれた文字列と文字列を連結することを好まないという背景で何が起こっているのか」です。
このことを考慮:
std::string str = "Hello " + "world"; // bad!
operator +
のrhsとlhsは両方ともchar*
sです。 2つのoperator +
sをとるchar*
の定義はありません(実際、言語では1つの記述は許可されていません)。その結果、私のコンパイラでは、「2つのポインターを追加できません」というエラーが発生します(配列の観点から物事を言いますが、それは同じ問題です)。
今これを考慮してください:
std::string str = "Hello " + std::string("world"); // ok
そこにisoperator +
の定義はconst char*
をlhsとして、std::string
をrhsとして取るので、誰もが幸せです。
これを好きなだけ連結チェーンに拡張できます。しかし、それは面倒になります。例えば:
std::string str = "Hello " + "there " + std::string("world"); // no good!
これは、lhsが+
に変換される前にchar*
を2つstd::string
sしようとしているため機能しません。しかし、これは問題ありません。
std::string str = std::string("Hello ") + "there " + "world"; // ok
std::string
に変換したら、+
を必要なだけchar*
s追加できるためです。
それでも混乱する場合は、いくつかの括弧を追加して結合規則を強調し、変数名をそれらの型に置き換えると役立つ場合があります。
((std::string("Hello ") + "there ") + "world");
((string + char*) + char*)
最初の手順は、標準ライブラリで定義されているstring operator+(string, char*)
を呼び出すことです。これらの2つのオペランドを結果に置き換えると、次の結果が得られます。
((string) + char*)
これはまさに私たちがやったことであり、まだ合法です。しかし、同じことを試してください:
((char* + char*) + string)
そして、最初の操作が2つのchar*
を追加しようとするため、スタックしています。
ストーリーの教訓:連結チェーンが機能することを確認する場合は、最初の2つの引数のいずれかが明示的にstd::string
型であることを確認してください。
AGE
は"42"
として定義されているため、行は次のとおりです。
str += "Do you feel " + AGE + " years old?";
に変換されます:
str += "Do you feel " + "42" + " years old?";
"Do you feel "
と"42"
は両方ともconst char[]
であるため、これは無効です。これを解決するには、std::string
にするか、+
を削除します。
// 1.
str += std::string("Do you feel ") + AGE + " years old?";
// 2.
str += "Do you feel " AGE " years old?";
2行目には、std::string
が関係しています(name
)。 char[] + std::string
、std::string + char[]
などに定義された操作があります。"Hello " + name
はstd::string
を提供し、これは" you are "
に追加され、別のストリングなどを提供します。
3行目では、あなたは言っている
char[] + char[] + char[]
配列を互いに追加することはできません。
このように生の文字列を連結することはできません。 operator+
は、2つのstd::string
オブジェクト、または1つのstd::string
と1つの生の文字列(操作の両側)でのみ機能します。
std::string s("...");
s + s; // OK
s + "x"; // OK
"x" + s; // OK
"x" + "x" // error
最も簡単な解決策は、最初に生の文字列をstd::string
に変換することです:
"Do you feel " + std::string(AGE) + " years old?";
もちろん、最初からマクロを使用しないでください。 C++はCではありません。const
を使用します。または、適切なコンパイラサポートを備えたC++ 11では、constexpr
を使用します。
この特定の場合、AGEが文字列リテラルであり、前後の文字列も文字列リテラルであるため、さらに簡単な修正方法は、「+」をすべて削除することです。 3行目は次のように記述できます。
str += "Do you feel " AGE " years old?";
これは、ほとんどのC/C++コンパイラが文字列リテラルを自動的に連結するためです。上記は次と同等です:
str += "Do you feel " "42" " years old?";
コンパイラーは以下に変換します:
str += "Do you feel 42 years old?";
コードにも同じ問題がありました。文字列を連結して文字列を作成していました。以下はコードの一部です。
int scannerId = 1;
std:strring testValue;
strInXml = std::string(std::string("<inArgs>" \
"<scannerID>" + scannerId) + std::string("</scannerID>" \
"<cmdArgs>" \
"<arg-string>" + testValue) + "</arg-string>" \
"<arg-bool>FALSE</arg-bool>" \
"<arg-bool>FALSE</arg-bool>" \
"</cmdArgs>"\
"</inArgs>");