新しいC ++標準の採用はすぐそこにあり、コンパイラ開発者は、プログラマーに、現在の言語に登場するいくつかの新機能を試す機会を与えます。 特に、Visual Studioの最新バージョンは、既に1回または2回以上記述されている多くの革新をサポートしています。 しかし、合成例を使用して機能を実証することと、戦闘モードでそれらを試すことです(明らかに、あなた自身の危険とリスクで)。 この記事はそのような実験の結果です。 だから。
ソース素材: C ++のソースを使用したゲームプロジェクト。 Qt(4.x)のユーザーインターフェイスであるBoost(1.40)を積極的に使用しました。
目的:このコンパイラとその新機能を使用して、プロジェクトをVisual Studio 2010に転送してさらに開発します(将来、gcc 4.5以前のバージョンに移行可能です)。
コードを転送する過程で、新しいコンパイラーによるアセンブリ中にクロールされたコンパイルエラーが修正されただけでなく、コードの表面処理も実行されました。 。 以下は、私が直面しなければならなかった問題とその解決方法の一部です。 はい、変更と最終的な再コンパイルを行った後、すべてが開始され、機能しました。
NULL vs nullptr
次のように、コードでQt(4.6.3)をビルドすると問題が発生しました。
std ::pair<SomeStruct*, SomeStruct*> pair( NULL , NULL );
このようなコードはVS 2005/2008で完全にコンパイルされますが、VS 2010では渡されません。正しいアセンブリのために、NULLをnullptrに置き換える必要があります。
std ::pair<SomeStruct*, SomeStruct*> pair( nullptr , nullptr );
問題は、std ::ペアにテンプレートコンストラクターがあることです。
template < class _Other1,
class _Other2>
pair(_Other1&& _Val1, _Other2&& _Val2)
これは以前のバージョンのSTLにはありませんでした。
ブースト::バインドvs標準::バインド
残念ながら、std :: bindの現在の実装(および仕様)は、多くの点で機能が劣り、boostに相当します。 特に:
1.この種のコードのコンパイルには問題があります。
struct SomeStruct
{
int m_dataMember;
int GetValue() const { return m_dataMember;}
};
void PrintValue( int val) { /* ... */ }
std ::vector<SomeStruct> vec;
std ::for_each(vec.begin(), vec.end(), std ::bind(PrintValue, std ::bind(&SomeStruct::m_DataMember, std ::placeholders::_ 1 )));
さらに、このオプション:
std ::transform(vec.begin(), vec.end(), std ::ostream_iterator( std :: cout , ' ' ), std ::bind(&SomeStruct::m_DataMember, std ::placeholders::_ 1 ));
または
std ::for_each(vec.begin(), vec.end(), std ::bind(PrintValue, std ::bind(&SomeStruct::GetValue(), std ::placeholders::_ 1 )));
正常にコンパイルします。 一連の実験により、バインディングチェーン内の参照型と非参照型を照合するときにstd :: bindの実装に問題があることが示されました。
2.バインダーの場合、算術演算および論理演算はオーバーロードされないため、これは「クラシック」です。
auto res = std ::find_if(vec.begin(), vec.end(), std ::bind(&SomeStruct::m_DataMember, std ::placeholders::_ 1 ) == 1 );
受け入れられません。
3.プレースホルダーは、std :: placeholdersのグローバル名前空間から削除されます。これにより、(使いやすくするために)フォームのエイリアスを入力する必要があります。
namespace ph = std ::placeholders;
バインドとラムダ
Lambda関数(その構文による)は、「古き良き」バインダーよりも多少「冗長」です。 コンテナ内で検索する前の例は、次のように書き換えることができます。
auto res = std ::find_if(vec.begin(), vec.end(), [](SomeStruct const & s)
{
return s.m_Value == 1 ;
});
どちらか(同じことですが、1行で)
auto res = std ::find_if(vec.begin(), vec.end(), [](SomeStruct const & s) { return s.m_DataMember == 1 ;});
比較のために:
auto res = std ::find_if(vec.begin(), vec.end(), boost::bind(&SomeStruct::m_DataMember, _1 ) == 1 );
-を優先するオプションは、それぞれ個別に決定する必要があります。
BOOST_FOREACHの簡素化
BOOST_FOREACHの実装は非常に重くて面倒です。 そして(私の意見では)ほとんどの場合、少なくとも2つの方法でそれを促進することができます。 一番の方法は、BOOST_FOREACHマクロの単純化された実装です。 たとえば、次のようにします。
#define FOREACH(Var, cont) \
if ( bool do_continue_ = true) \
for ( auto foreach_iter = std ::begin(cont); foreach_iter != std ::end(cont); ++ foreach_iter, do_continue_ = true) \
for (Var = *foreach_iter; do_continue_; do_continue_ = false)
メソッド番号2は、std :: for_each + lambdaの束に置き換えることです:
std ::for_each( std ::begin(vec), std ::end(vec), [](TestClass const & val)
{
std :: cout << val.m_Value << ' ' ;
});
どちらのオプションが望ましいか-再度決定するためには、所定の場所に必要です。 マクロを自分で再実装しました(コードの編集を減らすことができます)。 また、ラムダ関数からローカル変数にアクセスするには、キャプチャリストでの列挙が必要であることを忘れないでください。
ベクター<charT> vs basic_string <charT>
新しい標準の要件により、同様の構造から文字列の内容を順番に保存します(21.4.1、段落5):
std ::ifstream fs( /*...*/ );
// ...
std ::vector< char > buff(some_size);
fs.read(&buff[ 0 ], some_size);
return std :: string (buff.begin(), buff.end());
中間バッファをベクトルとして除外できます:
std :: string ret_val(some_size, '\0' );
fs.read(&ret_val[ 0 ], some_size);
return ret_val;
ささいなこと
-BOOST_AUTOはautoに置き換える意味があります。
-decltypeのBOOST_TYPEOF;
-cont.begin()/ cont.end()をより一般化されたstd :: begin(cont)/ std :: end(cont)に。