C ++ 11との前方互換性の実現


12

私は、いくつかのプラットフォームで実行する必要がある大規模なソフトウェアアプリケーションで作業しています。これらのプラットフォームの一部は、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名前空間に挿入することは違法です。それが理論です。私の質問は、実際には、前方互換性を達成する方法としてこれを行うことで害がありますか?


1
Boostはすでにかなりの量を提供しており、利用可能な場合はいつでも新しい機能を使用するためのコードをすでに持っているため、Boostが提供するものを使用して、それを実行できる可能性があります。もちろん、制限があります。ほとんどの新機能は、ライブラリベースのソリューションでは不十分であるため、特に追加されました。
ジェリーCo

はい、構文の変更ではなく、ライブラリレベルで実装できる機能について具体的に考えています。Boostは(シームレスな)前方互換性の問題に実際には対応していません。何かが足りない限り
...-mcmcc

Gcc 4.3には、すでにいくつかのC ++ 11機能があり、Rvalue-referencesがおそらく最も重要です。
Jan Hudec

@JanHudec:そのとおりです。悪い例。いずれにせよ、構文を完全にサポートしていないコンパイラーは他にもあります(たとえば、IBMのC ++コンパイラーのバージョン)。
mcmcc

回答:


9

私は最終的に C ++プログラムのレベルで前方互換性と後方互換性を維持しながら、最終的にはライブラリツールキットを作成する必要がありリリースの準備を進めていましたが、すでにリリースされています。一般に、機能(構文によってはエミュレートできないものもあります)でも構文でも「完全な」前方互換性が得られないことを受け入れる限り(おそらく、マクロ、代替名前空間を使用する必要があります)いくつかの事柄)その後、あなたはすべて設定されています。

実際に使用するのに十分なレベルでC ++ 03でエミュレートできる多くの機能があります。たとえば、Boostなどの煩わしさはありません。ヘック、C ++標準の提案でさえ、nullptrC ++ 03バックポートを提案しています。そして、たとえば、C ++ 11でありながら過去数年間のプレビューを行ったものすべてにTR1があります。それだけでなく、アサートバリアント、透過ファンクタなどのC ++ 14機能の一部は、C ++ 03で実装optional できます。

絶対にバックポートできないことを私が知っているのは、constexprとvariadicテンプレートの2つだけです。

ものを名前空間に追加すること全体の問題に関してstd、私の見解では、それは問題はないということです -まったく。最も重要で関連性の高いC ++ライブラリの1つであるBoostと、TR1:Boost.Tr1の実装について考えてみましょう。C ++を改善したい場合は、C ++ 11との前方互換性を確保し、定義によりC ++ 03ではないものに変えているので、回避するかまたは残す予定の標準をブロックすることは、簡単に言えば、逆効果です。純粋主義者は文句を言うでしょうが、定義上、それらを気にする必要はありません。

もちろん、結局(03)標準に従わないからといって、それを試みることができない、または喜んでそれを破るつもりはありません。それはポイントではありません。std名前空間に何を追加するかについて非常に慎重に制御し、ソフトウェアが使用される環境を制御する(つまり、テストを行う)限り、処理できない害はまったくありません。可能であれば、すべてを個別のネームスペースで定義し、usingディレクティブをネームスペースに追加するだけで、std「絶対に」入力する必要があるものを超えて追加することはありません。


更新(2013):元の質問のリクエストとして、担当者がいないために追加できないコメントの一部を見ると、C ++ 11およびC ++ 14の機能とそれらの移植性の程度のリストがありますC ++ 03へ:

  • nullptr:公式委員会のバックポートを考慮して完全に実装可能。「ネイティブ」タイプとして認識されるように、おそらくtype_traitsの特殊化も提供する必要があります。
  • forward_list:アロケータのサポートは、Tr1実装が提供できるものに依存しますが、完全に実装可能です。
  • 新しいアルゴリズム(partition_copyなど):完全に実装可能。
  • 括弧シーケンスからのコンテナ構造(例:)vector<int> v = {1, 2, 3, 4};完全に実装可能ですが、必要以上に冗長です。
  • static_assert:マクロとして実装された場合、ほぼ完全に実装可能です(コンマだけに注意する必要があります)。
  • unique_ptr:ほぼ完全に実装可能ですが、呼び出しコードからのサポートも必要になります(コンテナなどに保存するため)。ただし、以下を参照してください。
  • 右辺値参照:どれだけの値を取得するかによって、ほぼ完全に実装可能です(例:Boost Move)。
  • Foreach反復:ほぼ完全に実装可能で、構文は多少異なります。
  • 引数としてローカル関数を使用する(例:変換):ほぼ完全に実装可能ですが、構文は十分に異なります-たとえば、ローカル関数は呼び出しサイトで定義されず、直前に定義されます。
  • 明示的な変換演算子:実用的なレベルに実装可能(変換を明示的にする)、Imperfect C ++の「explicit_cast」を参照してください。しかし、static_cast<>ほとんど不可能なような言語機能との統合。
  • 引数の転送:上記の右辺値参照で与えられる実用的なレベルまで実装可能ですが、転送可能な引数を取る関数にN個のオーバーロードを提供する必要があります。
  • move:実用レベルまで実装可能(上記2つを参照)。もちろん、これから利益を得るには、修飾子コンテナとオブジェクトを使用する必要があります。
  • スコープ付きアロケーター:Tr1実装が支援しない限り、実際には実装できません。
  • マルチバイト文字タイプ:Tr1がサポートしない限り、実際には実装できません。ただし、C ++ 11を使用している場合でも、意図した目的のために、ICUなどの問題を処理するために特別に設計されたライブラリに依存する方が適切です。
  • 可変引数リスト:いくつかの手間をかけずに実装可能で、引数の転送に注意してください。
  • noexcept:コンパイラの機能に依存します。
  • 新しいautoセマンティクスとdecltype:は、コンパイラの機能に依存します-例:__typeof__
  • サイズの整数型(int16_tなど):コンパイラの機能に依存します-または、ポータブルstdint.hに委任できます。
  • 型属性:コンパイラの機能に依存します。
  • 初期化子リスト:私の知る限りでは実装できません。ただし、コンテナをシーケンスで初期化する場合は、「コンテナの構築」に関する上記を参照してください。
  • テンプレートのエイリアシング:私の知る限りでは実装できませんが、とにかく不要な機能であり::type、テンプレートには永遠にあります
  • 可変長テンプレート:私の知る限り実装できません。closeは、テンプレート引数のデフォルト設定であり、Nの専門化などが必要です。
  • constexpr:私の知る限りでは実装できません。
  • 均一な初期化:私の知る限りでは実装できませんが、デフォルトの -constructorの初期化は、Boostのvalue-initializedで実装できます。
  • C ++ 14 dynarray完全に実装可能。
  • C ++ 14 optional<>:C ++ 03コンパイラがアライメント設定をサポートしている限り、ほぼ完全に実装可能です。
  • C ++ 14透過ファンクタ:ほぼ完全に実装可能ですが、クライアントコードは、たとえばstd::less<void>、動作させるために明示的にeg .: を使用する必要があります。
  • C ++ 14の新しいアサートが(のようなバリアントassure):完全に実現可能な、あなたがしたい場合は、有効にしたい場合は代わりにスロー近く、完全に実装可能な、主張しています。
  • C ++ 14タプル拡張(タプル要素をタイプ別に取得):完全に実装可能であり、機能提案で説明されている正確なケースでコンパイルに失敗することさえあります。

(免責事項:これらの機能のいくつかは、上でリンクしたC ++バックポートライブラリに実装されているので、「完全に」または「ほぼ完全に」と言ったときに何を言っているか知っていると思います。)


6

これは基本的に不可能です。検討してくださいstd::unique_ptr<Thing>。右辺値参照をライブラリとしてエミュレートできる場合、それは言語機能ではありません。


1
「可能な限り」と言いました。明らかに、いくつかの機能は#ifdefの後ろに残すか、まったく使用しない必要があります。std :: move()は、シンタックスをサポートできるものです(機能ではありませんが)。
mcmcc

2
実際、右辺値参照の提案はライブラリベースのソリューションに言及しています!
1月Hudec

より具体的には、C ++ 03の特定のクラスに移動セマンティクスを実装することが可能であるため、std::unique_ptrそこで定義できるはずですが、右辺値参照の他の機能はC ++ 03で実装できないため、std::forward不可能です。もう1つはstd::unique_ptr、コレクションがすべてを置き換えるまで移動セマンティクスを使用しないため、コレクションは役に立たないということです。
1月Hudec

@JanHudec:を定義することはできませんunique_ptr。の失敗を見てくださいauto_ptrunique_ptr実際には、セマンティクスが言語機能によって基本的に有効化されたクラスの教科書の例です。
DeadMG

@DeadMG:いいえ、それunique_ptrは言語機能によって根本的に可能になったわけではありません。ただし、その機能がなければ便利ではありません。完全な転送がなければ多くの場合使用できないため、完全な転送にはその機能が必要です。
1月Hudec

2
  1. Gccは4.3でC ++ 11(当時はまだC ++ 0x)の導入を開始しました。この表は、右辺値参照と使用頻度の低い他の機能が既にあることを示しています(-std=c++0x有効にするオプションを指定する必要があります)。
  2. C ++ 11の標準ライブラリへの多くの追加はTR1ですでに定義されており、GNU stdlibc ++はそれらをstd :: tr1名前空間で提供します。したがって、適切な条件付き使用を行ってください。
  3. BoostはほとんどのTR1関数を定義し、TR1名前空間にそれを持たない場合は挿入できます(ただし、GNU stdlibc ++を使用する場合はVS2010もgcc 4.3も同様です)。
  4. std名前空間に何かを置くことは、「未定義の動作」です。つまり、仕様は何が起こるかを述べていません。ただし、特定のプラットフォームで標準ライブラリが何かを定義しないことがわかっている場合は、先に進んで定義してください。必要なものと定義できるものを各プラットフォームで確認する必要があることを期待してください。
  5. 右辺値参照提案、N1690では、C ++ 03での移動セマンティクスの実装方法について言及しています。それは代用に使用できましたunique_ptr。ただし、実際には移動セマンティクスを使用するコレクションに依存しているため、あまり有用ではありません。C++ 03のコレクションは明らかにそうではありません。

1
GCCについては正しいのですが、残念ながら、他の(非GCC)コンパイラもサポートする必要があります。#4の箇条書きは、私が尋ねている質問の核心です。#5は興味深いですが、これらの古いプラットフォームでムーブセマンティクス(コピーの最適化)をサポートするのではなく、コンパイル可能な構文として単に "std :: move()"をサポートしたいと考えています。
mcmcc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.