C++14常用新特性まとめ

7847 ワード

1.戻り値タイプ導出(Return type deduction)
なぜリターンタイプ導出はC++プログラムに花を添えるのか.まず、標準ライブラリコンテナを検索するときに反復器を返すなど、非常に複雑なタイプを返さなければなりません.Auto返却タイプにより、関数がより読みやすく、書きやすくなります.次に、この原因はそれほど明らかではないかもしれませんが、auto戻りタイプを使用すると、再構築能力を強化することができます.例を挙げると、次のコードを考慮します.
#include 
#include 
#include 

struct record {
std::string name;
int id;
};

auto find_id(const std::vector &people,
const std::string &name)
{
auto match_name = [&name](const record& r) -> bool {
return r.name == name;
};
auto ii = find_if(people.begin(), people.end(), match_name );
if (ii == people.end())
return -1;
else
return ii->id;
}

int main()
{
std::vector roster = { {"mark",1},
{"bill",2},
{"ted",3}};
std::cout << find_id(roster,"bill") << "
"; std::cout << find_id(roster,"ron") << "
"; }

この例ではfind_idはintを返すよりautoを返すほうが脳力を節約することはありません.しかし、私がrecord構造体を再構築することを決めたら、生きているのだろうか.今回はrecordオブジェクトで1つの整数を使用して1人だけをマークするのではなく、新しいGUIDタイプを使用します.
struct record {
	std::string name;
	GUID id;
};

recordオブジェクトに対するこの変更は、関数の戻りタイプなど、一連の連鎖反応をもたらします.しかし、関数の戻り値に自動タイプ導出を使用すると、コンパイラはこれらの変化に黙って対応します.大規模なエンジニアリングで開発されたC++プログラマーは、この問題に詳しい.単一のデータ構造の変更は、元のコードの反復、変数、パラメータ、および戻りタイプの変更を無停止にします.autoの広範な使用はこのような仕事の大部分を削減することができる.
戻り値としてautoを使用するとすぐに効果が現れるのはreality of it's doppelganger,decltype(auto)であり,タイプ導出のルールもある.次のコードクリップなど、タイプ情報を自動的に取得できます.
template
	struct finder {
	static decltype(Container::find) finder1 = Container::find;
	static decltype(auto) finder2 = Container::find;
};

2.汎用lambdasのもう一つのautoがこっそり潜伏している場所はlambdaパラメータの定義にある.autoタイプ宣言を使用してlambdaパラメータを定義することは、テンプレート関数の作成とほぼ同じです.Lambdaはパラメータ導出タイプに基づいて特定のインスタンス化を行う.
これは、異なるコンテキストで再利用可能なlambdasを作成するのに便利です.次の簡単な例では、lambdasが標準ライブラリ関数として使用する述語(predicate)を作成します.C++11の世界では、私はそれぞれ整数加算で、文字列加算はlambdaをインスタンス化しています.
汎用lambdaがあれば、単一のlambdaを定義することができます.文法にはキーワードtemplateは含まれていませんが、C++汎用プログラミングのさらなる拡張です.
#include 
#include 
#include 
#include 

int main()
{
	std::vector ivec = { 1, 2, 3, 4};
	std::vector<:string> svec = { "red",
	"green",
	"blue" };
	auto adder = [](auto op1, auto op2){ return op1 + op2; };
	std::cout << "int result : "
	<< std::accumulate(ivec.begin(),
	ivec.end(),
	0,
	adder )
	<< "
"; std::cout << "string result : " << std::accumulate(svec.begin(), svec.end(), std::string(""), adder ) << "
"; return 0; }

次の結果が得られます.
int result : 10string result : redgreenblue
匿名inline lambdasをインスタンス化しても,前述したように汎用パラメータは依然として有用である.データ構造が変化したり、APIsの関数が変更されたりした場合、汎用lambdasを調整するには、再コンパイルするだけで、再実装する必要はありません.
std::cout << "string result : "
<< std::accumulate(svec.begin(),
svec.end(),
std::string(""),
[](auto op1,auto op2){ return op1+op2; } )
<< "
";

3.初期化されたlambdasキャプチャ(Initialized lambda captures)
C++11ではlambdaキャプチャ特化(lambda capture specification)の概念に適応し始めなければならない.この宣言は、closureを作成するときにコンパイラを起動します.lambdaは関数のインスタンスを定義し、lambdaの役割ドメイン以外の関数にバインドされた変数を定義します.
初期の導出戻りタイプの例では、述語で文字列のソースを検索するために、単一の変数名を取得するlambda定義を実現しました.
auto match_name = [&name](const record& r) -> bool {
	return r.name == name;
};
	auto ii = find_if(people.begin(), people.end(), match_name );

この特殊なキャプチャにより、lambdaは参照による変数へのアクセス権限を取得します.キャプチャは値で実行することもでき、両方の場合、変数の使用方法はC++の直感に合致します.値別キャプチャは、lambdaがローカル変数のコピー上で動作することを意味し、参照別キャプチャは、lambdaが周辺役割ドメインの変数自体で動作することを意味する.
これらはすべて良いですが、それに伴う限界もあります.委員会が処理しなければならないことはmove-onlyの意味を使ってキャプチャ変数を初期化することだと思います.これは何を意味しますか?lambdaがパラメータの受信機になると考える場合,move意味を用いて外部変数をキャプチャしたい.例を挙げて、lambdaにmove-only uniqueを受信する方法を考えます.ptrパラメータ.最初の試みは値によって取得されましたが、失敗しました.
std::unique_ptr p(new int);
*p = 11;
auto y = [p]() { std::cout << "inside: " << *p << "
";};

unique_のためコンパイルエラーが生成されます.ptrにはコピー構造関数がありません.コピーを禁止することを考えています.リファレンスキャプチャに変更するとコンパイルできますが、予想される効果は得られません.つまり、値moveをローカルにコピーすることでパラメータを受信します.最後に、ローカル変数を作成してから、取得したリファレンスにstd::move()を呼び出すことで完了できますが、効率は高くありません.
この問題は、取得文の構文を変更することで修正できます.キャプチャ変数を1つだけ宣言するのではなく、初期化することもできます.次の例を見てください:auto y=[&r=x,x=x+1]()->int{...}
auto y = [&r = x, x = x+1]()->int {...}

上記のコードはxのコピーをキャプチャし、xに1を追加します.この例は分かりやすいが、move-only変数を受信するためにこの新しい構文の値をキャプチャしたかどうかは分からない.この新しい文法を使用する例は次のとおりです.
#include 
#include 

int main()
{
	std::unique_ptr p(new int);
	int x = 5;
	*p = 11;
	auto y = [p=std::move(p)]() { std::cout << "inside: " << *p << "
";}; y(); std::cout << "outside: " << *p << "
"; return 0; }

この例では、取得された値pはmoveの意味で初期化され、ローカル変数が宣言されていない場合にポインタ:inside:11 Segmentation fault(core dumped)が有効に受信される
この嫌な結果は、pがキャプチャされ、lambdaにmoveされた後、コードがpを理解して参照することです.
4.[[廃棄][[deprecated]]属性
 
初めてdeprecatedプロパティを見たのはjavaで、少し嫉妬していることを認めました.多くのプログラマーにとってコード腐敗(rot)は大きな問題である.(コードの削除を奨励したことがありますか?しかし、私はそんなことをしたことがありません).この新しいプロパティは、この問題を解決するシステムレベルの方法を提供します.
簡単に使えます.ラベル[[deprecated]]を宣言の前に置けばいいです.宣言はクラス、変数、関数、または他のものです.結果は次のようになります.
[[deprecated]] flaky {};

 
プログラムがdeprecatedエンティティを使用すると、コンパイラが反応する必要があったが、コード実装者に残された.多くの人が何らかの警告を見たいし、手当たり次第にこのwarningを消すことができることはよく知られています.例を挙げるとclang 3.4 deprecatedクラスをインスタンス化すると、dep.cpp:14:3:warning:'flaky'is deprecated[-Wdeprecated-declarations]flaky f;dep.cpp:3:1: note: 'flaky' declared hereflaky {^
C++の属性タグ構文は少し慣れていないように見えます.プロパティリストでは、classやenumなどのキーワードの後、エンティティ名の前に[[deprecated]]が配置されます.このタグには、情報パラメータを含む別の形式があります.開発者がこの情報をどのように書くかを決めます.clang3.4この情報を無視した.
次のコードクリップを見てください.
class
[[deprecated]] flaky {
};

[[deprecated("Consider using something other than cranky")]]
int cranky()
{
return 0;
}

int main()
{
flaky f;
return cranky();
}

5.バイナリ数字と数字区切り記号
2つの新しい機能は驚天動地ではありませんが、彼らは確かに良い文法構造の改善を代表しています.このような小さな変更はコードの可読性を改善し,バグ数をさらに減少させた.C++プログラマーは、すでに10進数、16進数、および使用されていない8進数を含む標準にもう1つのバイナリ数を作成することができます.バイナリ数字は、接頭辞0 bの直後の数字を使用する.アメリカとイギリスでは、カンマを数値区切り記号として使用します.例えば、$1000000です.この書き方は本当に読者に便利で、私たちの脳が長い数字を処理するときにもっと簡単になります.同様の理由でC++標準委員会はデジタル区切り記号を追加した.数値には影響しませんが、ブロック化することで数字の読み書きが容易になります.
数字区切り記号にはどんな文字が使われていますか?C++では基本的に各句読点が特定の特性で使用されているため,明らかな選択はない.最後の選択は、C++の百万数を1'000'000.00と表すように、単一引用符文字を使用することです.区切り記号は数値に何の影響もないことを覚えておいてください.そのため、百万数は以下のように表すことができます.1'0'00'0'00.00.次の例では、2つの新しいプロパティを使用します.
#include 

int main()
{
int val = 0b11110000;
std::cout << "Output mask: "
<< 0b1000'0001'1000'0000
<< "
"; std::cout << "Proposed salary: $" << 300'000.00 << "
"; return 0; }
の結果も予想通りでした.
Output mask: 33152Proposed salary: $300000
6.残存特性
c++の他の新しい特性は、これ以上説明する必要はありません.変数テンプレートは、変数上のテンプレートの拡張です.常に使用される例は変数piの実装である.doubleとして実装されると、変数は3.14を返し、intとして実装されると3を返し、stringとして実装されると「3.14」または「pi」を返すことができ、これは素晴らしい特性であり、以前は実装されていた.変数テンプレートの構文と意味とクラステンプレートは基本的に同じです.追加の学習を必要とせずに使用できます.constexpr関数の制限は緩和されます.たとえば、case文とif文を内部で使用したり、ループやその他を使用したりする複数の戻り値があります.これはコンパイラでできることを拡張し,テンプレートの導入に翼を挿した.その他の小さな特性には、メモリに指定されたサイズ(sized deallocations)といくつかの構文の整理(tidying)が含まれます.
関連ブログ:
C++11常用新特性まとめ原文リンク