複数のプラットフォームで実行する必要のある大規模なソフトウェアアプリケーションで作業しています。これらのプラットフォームの一部はC++ 11の一部の機能をサポートし(例:MSVS 2010)、一部はサポートしていません(例:GCC 4.3.x)。この状況は数年間続くと思います(私の推測では3〜5年)。
そこで、互換性インターフェイスをセットアップして、(可能な限り)最小限のメンテナンスで古いコンパイラでコンパイルできるC++ 11コードを人々が記述できるようにしたいと思います。全体として、目標は、#ifdefを可能な限り最小限に抑えながら、それらをサポートするプラットフォームで基本的なC++ 11構文/機能を有効にし、サポートしていないプラットフォームでエミュレーションを提供することです。
Std :: move()から始めましょう。互換性を実現する最も明白な方法は、次のようなものを共通のヘッダーファイルに入れることです。
#if !defined(HAS_STD_MOVE)
namespace std { // C++11 emulation
template <typename T> inline T& move(T& v) { return v; }
template <typename T> inline const T& move(const T& v) { return v; }
}
#endif // !defined(HAS_STD_MOVE)
これにより、人々は次のようなものを書くことができます
std::vector<Thing> x = std::move(y);
...免責。それは彼らがC++ 11で望んでいることをし、C++ 03でそれができる最善を尽くします。最後に最後のC++ 03コンパイラを削除しても、このコードはそのままにしておくことができます。
ただし、標準によれば、std
名前空間に新しいシンボルを挿入することは違法です。それが理論です。私の質問は:実際的に言えば前方互換性を実現する方法としてこれを行うことに害はありますか?
私はC++プログラムで前方互換性と後方互換性のレベルを維持しながら、ずっと働いてきました 最終的にライブラリツールキットを作成する必要が生じるまで 、 リリースの準備をしています すでにリリースされています。一般的に、構文ではなく機能(フォワードエミュレートできないものもあります)でも "完全な"前方互換性が得られないことを受け入れる限り、マクロや代替の名前空間を使用する必要がありますいくつかのこと)そして、あなたはすべて準備が整いました。
C++ 03で実際に使用するのに十分なレベルでエミュレートできる機能はたくさんあります。たとえば、Boostなどの面倒な作業はありません。ヘック、nullptr
のC++標準の提案でさえ、C++ 03バックポートを提案しています。そして、たとえばC++ 11のすべてにTR1がありますが、何年も前からプレビューがありました。それだけでなく、一部のC++ 14アサートバリアント、透過ファンクタ、optional
canなどの機能をC +に実装する+03!
絶対にバックポートできないことがわかっている唯一の2つは、constexprテンプレートとvariadicテンプレートです。
名前空間std
に要素を追加することに関しては、問題ではない-であると私は考えています。最も重要で関連性の高いC++ライブラリの1つであるBoostと、それらのTR1の実装を考えてみてください:Boost.Tr1。 C++を改善したい場合は、C++ 11との上位互換性を確保し、定義によりnotC++ 03に変換するため、ブロックします。回避しようとする、またはとにかく残そうとする標準を超えた自分は、単純に言えば逆効果です。純粋主義者は文句を言うでしょうが、当然のことながら、それらを気にする必要はありません。
もちろん、結局のところ(03)の標準に従わないからといって、試してみることができない、またはgleefullyに行くことになるわけではありませんそれを壊す周り。それはポイントではありません。 std
名前空間に何を追加するかについて非常に注意深い制御を維持し、ソフトウェアが使用される環境を制御できる(つまり、テストを行う)限り、追跡できないはずはありません。まったく害。可能であれば、すべてを別の名前空間で定義し、using
ディレクティブを名前空間std
に追加するだけで、「絶対に」入れる必要があるもの以外に何も追加しないようにします。 Boost.TR1が行うことの多かれ少なかれ。
更新(2013):元の質問のリクエストとして、担当者がいないために追加できないコメントがいくつかあるので、C++ 11とC++のリストを示します。 14の機能とC++ 03への移植性の程度:
nullptr
:完全公式委員会のバックポートを考慮して実装可能。 「ネイティブ」タイプとして認識されるように、type_traitsの特殊化も提供する必要があります。forward_list
:完全実装可能ですが、アロケータのサポートは、Tr1実装が提供できるものに依存しています。vector<int> v = {1, 2, 3, 4};
):fully実装可能ですが、望みよりも幅が広くなります。static_assert
:マクロとして実装すると、ほぼ完全に実装可能です(コンマに注意するだけで十分です)。unique_ptr
:ほぼ完全に実装可能ですが、コードの呼び出しからのサポートも必要です(それらをコンテナーなどに格納するため)。以下を参照してください。static_cast<>
などの言語機能との統合はほぼ不可能です。noexcept
:コンパイラの機能によって異なります。auto
セマンティクスとdecltype
:はコンパイラの機能に依存します-例:__typeof__
。int16_t
など):コンパイラの機能によって異なります。または、ポータブルstdint.hに委任することもできます。::type
が永遠に含まれていますconstexpr
:私の知る限りでは実装できません。dynarray
:完全に実装可能。optional<>
:C++ 03コンパイラがアライメント設定をサポートしている限り、ほぼ完全に実装可能です。std::less<void>
を明示的に使用して機能させる必要があります。assure
など):完全アサートが必要な場合は実装可能、代わりにスローを有効にする場合はほぼ完全に実装可能。(免責事項:これらの機能のいくつかは、上でリンクしたC++バックポートライブラリに実装されているので、「完全に」または「ほぼ完全に」と言ったとき、私が話していることはわかっていると思います。)
これは根本的に不可能です。考慮してくださいstd::unique_ptr<Thing>
。右辺値参照をライブラリとしてエミュレートすることが可能である場合、それは言語機能ではありません。
-std=c++0x
オプションを指定する必要があります)。std
名前空間に何かを入れることは「未定義の動作」です。つまり、仕様には何が起こるかは記載されていません。ただし、特定のプラットフォームで標準ライブラリが何かを定義していないことがわかっている場合は、先に進んで定義してください。必要なものと定義できるものを各プラットフォームで確認する必要があることを期待してください。unique_ptr
の代わりに使用できます。ただし、移動のセマンティクスを実際に使用するコレクションに依存しており、C++ 03のコレクションは明らかにそうではないため、あまり役に立ちません。