std::string
それ自体はしません。
さまざまな選択肢があり、多かれ少なかれエレガントで、多かれ少なかれ長所と短所があります。それらを比較してみましょう
カプセル化によるラップ
おそらく最もクリーンな解決策: std::string を含み、変換を実行する ctor と代入を使用できるクラスを作成します。
- 問題: std::sting には 100 を超えるメソッドがあります。クラスでそれらすべてを公開する場合は、ラップされたものを呼び出すためだけにすべてのホース関数を作成する準備をしてください。これはクリーンな「生産性の問題」であり、OOP 熱狂者は対処していないようです...入力された文字によって支払われている可能性があります... :-)
- 利点: ランタイム ポリモーフィズム (std::string でサポートされていない) が誤って機能しないため、コードがより安全になります。
「部分」ラップ
前と同じですが、いくつかの重要なメソッドにのみ関連するか、明示的なコーディングが必要です。
典型的な実装は次のとおりです。
次のことができます。
class llstring
{
public:
//just esplicitate a default
llstring() :m() {}
//this wors for all the std::string contructors but the ones specifically defined here
template<class T, class... TT>
llstring(T&& t, TT&&... tt) :m(std::forward<T>(t), std::forward<TT>(tt)...)
{}
// copy and move defaulted: just call the memebr ones
llstring(const llstring&)=default;
llstring(llstring&&) =default;
//impose conversion
llstring(const std::string& s) :m(lowercase(s)) {}
llstring(const char* s) :m(lowercase(s)) {}
//assign and transfer defaulted
llstring& operator=(const llstring&)=default;
llstring& operator=(llstring&&)=default;
//impose conversion
llstring& operator=(const std::sting& s) { m = lowercase(s); return *this; }
llstring& operator=(const char* s) { m = lowercase(s); return *this; }
//gets the "value"
const std::string& str() const { return m; }
private:
std::string m;
};
このクラス自体は、アルゴリズムや操作を行うことはできませんがstd::string
、str()
. また、変換によって取得される std::string の結果を受け入れることができます。
おそらく、再コーディングとメンテナンスのリスクの間の適切な妥協案です
継承する
メンバーではなく、ベースとして std::string 。コードは上記と同様です (コンストラクトまたは代入時に変換する方法を提供する必要があります)。
利点: 元の std::string のインターフェースと動作が自動的に公開されるため、すべての std::string メソッドが機能し、アクセス可能になります。
ニュートラル: std::string からの前方 (設計による) および後方 (基本継承による) の両方の変換が機能します。これにより、llstring を通過しない特定の操作であいまいさが生じる可能性があります。それ自体は問題ではありませんが、関数名の解決とバインドがどのように行われるかについては十分に理解しておく必要があります。言語は明確に規定されていますが、平均的なプログラマーには必ずしも知られていない言語の側面の 1 つです。
欠点: llstring は std::string に関して多態的に動作しない多態的な動作を公開します (デストラクタを含め、どのメソッドも仮想ではありません)。 'llstring` を指している場合)。
llstring
と string の両方が値型であることを考えると、これは通常発生しないはずです (30 年間、私は単一のnew std::string
orを書いたことはありませんdelete pstring
)。しかし、これはいずれにせよ、たとえ OOP オブジェクトでなくても、string-s にも適用する古典的な OOP ルールを装う OOP 狂信者のすべての暴言をキャッチします。
しかし、別の-IMHOより微妙な-リスクがあります。llstringとstringの間の複合式では、すべての中間結果がstringになります。また、中間操作は途中で変換されません。そして、それはすべて暗黙的です。繰り返しになりますが、言語仕様は明確に定義されていますが、すべてを制御するのは容易ではないかもしれません。まだ割り当てられていない中間結果の検索は失敗する可能性があります... 内部に予期しない大文字が含まれているためです。
逆変換
あなたが尋ねたものとは正確には異なりますが...問題をより適切に反転させている可能性があります。
「宛先に到達するときに変換する」の代わりに、「ソースを離れるときに変換する」:
文字列から暗黙的に変換を取得し、明示的な str() 関数を持つ代わりに、n 文字列から明示的な構造を取り (変換なしでも)、暗黙的な変換を持つラッパー (上記の「部分ワープ」のように) を作成します。文字列へ( operator std::string() { return lowercase(m); }
)
これは、あなたが求めたものとは逆に機能します。大文字の文字列の存在が許可されるポイントの数が、プログラム内の文字列全体をほとんど尊重しない場合 (常に小文字であると想定できます)、および間に実装できるすべての std::string 操作を許可できる場合は良いでしょう。小文字の文字列値が大文字の文字列を生成することはありません。
編集: char_traits ソリューション
Nawaz の投稿の後に追加:
解決策は、 char を別のセマンティクスに準拠させることにより、動作( valueではなく)を変更しようとします。
- 利点: シンプルで、大きなラッパーを必要としません。コーディングが速い。
- 欠点: 意図したとおりではない可能性があります: std::string 関数はすべてアクセス可能であり、コピーが文字列の内容を変更する唯一の方法ではない可能性があるため、(いずれにせよ) 大文字の文字が決して存在しないことは認められませんそれ。そのコピーが文字列値を変更する唯一の方法になることを許可できない限り。
注: と同様string
に、仮想デストラクタもchar_traits
ありませんが、文字列とは異なり、OOP 熱狂者は通常、文字列からの継承について叫ぶことはありません。そして、尋ねられた場合、おそらく「char_traits に動的割り当てはありません」と言うでしょう。さようならコヒーレンス。
結論は
There is no "perfect solution" with "low cost". All of them are somehow inperfect at some stage