C++11:初心者は学びやすく、老兵は使いやすい
1 C++11ではvector>の2つの括弧間のスペースを削除します.つまり、C++11ではvectorと書くことができます.コンパイラでは>>を右シフト記号とは考えません.
2 auto:C++の各変数を使用する前に定義する必要があります.これは、スクリプト言語の変数のようにx=1を動的言語と呼ぶことはできません.静的言語と動的言語の主な違い:静的言語タイプチェックはコンパイルフェーズで発生し、動的言語タイプチェックは実行フェーズで発生します.C++11ではautoとdecltypeが静的言語から動的言語に少し近づくことを実現した.autoはストレージタイプの識別子ではなく、ジオメトリC言語でatuo、staticなどの変数の違いを大きく話していたことを覚えています.現在、autoはC++11でタイプインジケータであり、元のC++98のストレージタイプ識別子の意味は捨てられています.autoは、コンパイラが宣言した変数タイプがコンパイル時に導出され、atuoがプレースホルダであることに相当し、コンパイル時に変数のタイプを決定することをコンパイラに伝える.例えば、atuo x=1;コンパイル時のxのタイプはintと自動的に推定され、int x=1に等価である.
1つの実用的な点はstd::vector::iterator it=vec.begin();auto it=vecと書くことができます.begin()
atuoは、次のようなタイプの柔軟性を追加しました.
autoは同じ文で複数の変数を推定し、最初のatuoのタイプは後の変数の性であり、左から右に導出されます.
3 decltype:タイプ導出
typeid(クラス名).name()はタイプの名前、typeid(クラス名)を返すことができます.hash_code()は、typeid(クラス1)のようなタイプに対応する一意のhash値を返す.hash_code()==typeid(クラス名2).hash_code().is_same<クラス名1,クラス名2>::valueは2つのクラスが同じかどうかを判断することもできます.
decltypeとusingを組み合わせた例:
result_of実装はdecltypeに基づいており,関数の戻り値タイプを推定するためにヘッダファイル:
1)eが括弧付きタグ式(キーワード、字面量などのコンパイラが使用するタグを除くプログラマがカスタマイズしたタグ)またはクラスメンバーアクセス式である場合、decltype(e)はeが命名したエンティティのタイプである.eがリロードされた関数名である場合、コンパイルエラーが発生します.
2)そうでない場合、eタイプがTであると仮定し、eが関数非参照戻り値などのデッド値である場合、decltype(e)はT&&&&
3)そうでない場合、eが左値であればdecltype(e)がT&であり、これは左値ルールである
4)そうでない場合、decltype(e)はTの例である.
4トレース戻りタイプ
まず、例を見てみましょう.
2 auto:C++の各変数を使用する前に定義する必要があります.これは、スクリプト言語の変数のようにx=1を動的言語と呼ぶことはできません.静的言語と動的言語の主な違い:静的言語タイプチェックはコンパイルフェーズで発生し、動的言語タイプチェックは実行フェーズで発生します.C++11ではautoとdecltypeが静的言語から動的言語に少し近づくことを実現した.autoはストレージタイプの識別子ではなく、ジオメトリC言語でatuo、staticなどの変数の違いを大きく話していたことを覚えています.現在、autoはC++11でタイプインジケータであり、元のC++98のストレージタイプ識別子の意味は捨てられています.autoは、コンパイラが宣言した変数タイプがコンパイル時に導出され、atuoがプレースホルダであることに相当し、コンパイル時に変数のタイプを決定することをコンパイラに伝える.例えば、atuo x=1;コンパイル時のxのタイプはintと自動的に推定され、int x=1に等価である.
1つの実用的な点はstd::vector
atuoは、次のようなタイプの柔軟性を追加しました.
class PI {
public:
double operator* (float v) {
return (double)val * v; //
}
const float val = 3.1415927f;
};
int main() {
float radius = 1.7e10;
PI pi;
auto circumference = 2 * (pi * radius);//atuo , PI operator* ,main
}
atuoでは、次のようなオーバーフローの問題は解決できません.unsigned int a=4294967295;//
unsigned int b=1;
auto c=a+b;//c=0
atuoは、次のようなプラットフォーム間で一定のメリットをもたらします.auto var=strlen("hello world")//strlen 32 4 ,64 8 , auto
autoにより、テンプレートの柔軟性が向上しました.template<typename T1, typename T2>
double Sum(T1 & t1, T2 & t2) {// double auto ,
auto s = t1 + t2; // s ,
return s;
}
int main() {
int a = 3;
long b = 5;
float c = 1.0f, d = 2.3f;
auto e = Sum(a, b); // s long
auto f = Sum(c, d); // s float
}
autoマクロの驚くべき例:#define Max1(a, b) ((a) > (b)) ? (a) : (b)// a b a b
#define Max2(a, b) ({ \
auto _a = (a); \ // a _a ,
auto _b = (b); \
(_a > _b) ? _a: _b; })
int main() {
int m1 = Max1(1*2*3*4, 5+6+7+8);
int m2 = Max2(1*2*3*4, 5+6+7+8);//
}
atuoとポインタと参照の関係:int x;
int * y = &x;
double foo();
int & bar();
auto * a = &x; // int*, auto* auto
auto & b = x; // int&, atuo&
auto c = y; // int*
auto * d = y; // int*
auto * e = &foo(); // ,
auto & f = foo(); // , nonconst
auto g = bar(); // int
auto & h = bar(); // int&
CV制限子:auto,volatile,constはそれぞれタイプ表示子、揮発性、定数を表す.double foo();
float * bar();
const auto a = foo(); // a: const double
const auto & b = foo(); // b: const double&
volatile auto * c = bar(); // c: volatile float*
auto d = a; // d: double, auto cv
auto & e = a; // e: const double &, auto& cv
auto f = c; // f: float *
volatile auto & g = c; // g: volatile float * &
autoは、初期化リストとnewとともに使用できます.#include <initializer_list>
auto x = 1;
auto x1(1);
auto y {1}; // auto
auto z = new auto(1); // new
autoは同じ文で複数の変数を推定し、最初のatuoのタイプは後の変数の性であり、左から右に導出されます.
auto a=1,b=2;// int a=1; int b=2; auto, auto
autoが適用されない場所:#include <vector>
using namespace std;
void fun(auto x =1){} // 1: auto ,
struct str{
auto var = 10; // 2: auto ,
};
int main() {
char x[3];
auto y = x;
auto z[3] = x; // 3: auto ,
// 4: auto ( ),
vector<auto> x = {1};
}
3 decltype:タイプ導出
typeid(クラス名).name()はタイプの名前、typeid(クラス名)を返すことができます.hash_code()は、typeid(クラス1)のようなタイプに対応する一意のhash値を返す.hash_code()==typeid(クラス名2).hash_code().is_same<クラス名1,クラス名2>::valueは2つのクラスが同じかどうかを判断することもできます.
int i;
decltype(i) j = 0;
cout << typeid(j).name() << endl; // "i", g++ integer
float a;
double b;
decltype(a + b) c;
cout << typeid(c).name() << endl; // "d", g++ double
decltypeはautoのように変数宣言の初期化式から変数のタイプを取得するのではなく、decltypeは常に通常の式をパラメータとして、その式のタイプを返します.decltypeは、autoと同様にdecltypeもコンパイル中に行われる別の変数を定義するために得られるタイプである.decltypeとusingを組み合わせた例:
using size_t=decltype(sizeof(0));//size_t
decltypeはauto it=vecのようにすることができる.begin()は、標準コンテナと同様に使用されます. vector<int> vec;
typedef decltype(vec.begin()) vectype;
vectype i; // auto
for (i = vec.begin(); i < vec.end(); i++) {
//
}
for (decltype(vec)::iterator i = vec.begin(); i < vec.end(); i++) {
//
}
decltypeは匿名タイプを再利用できます.enum class{K1, K2, K3}anon_e; //
union {
decltype(anon_e) key;
char* name;
}anon_u; // union
struct {
int d;
decltype(anon_u) id;
}anon_s[100]; // struct
int main() {
decltype(anon_s) as;//
as[0].id.key = decltype(anon_e)::K1; //
}// anon_e decltype ,
decltype前の「autoがテンプレートの柔軟性を向上させた」例を再構築します.// s decltype(t1 + t2)
template<typename T1, typename T2>
void Sum(T1 & t1, T2 & t2, decltype(t1 + t2) & s) {// s
s = t1 + t2;
}
int main() {
int a = 3;
long b = 5;
float c = 1.0f, d = 2.3f;
long e;// e , Sum, ,
float f;
Sum(a, b, e); // s long
Sum(c, d, f); // s float
}
decltypeは、テンプレートをインスタンス化するために使用されます.int hash(char*);// hash
//map<char*, decltype(hash)> dict_key; // ,hash ,hash(nullptr) decltype
map<char*, decltype(hash(nullptr))> dict_key;
テンプレートクラスresult_of実装はdecltypeに基づいており,関数の戻り値タイプを推定するためにヘッダファイル
typedef double (*func)();
result_of<func()>::type f; // func() ,double
decltype(e)推定の4つのルール:1)eが括弧付きタグ式(キーワード、字面量などのコンパイラが使用するタグを除くプログラマがカスタマイズしたタグ)またはクラスメンバーアクセス式である場合、decltype(e)はeが命名したエンティティのタイプである.eがリロードされた関数名である場合、コンパイルエラーが発生します.
2)そうでない場合、eタイプがTであると仮定し、eが関数非参照戻り値などのデッド値である場合、decltype(e)はT&&&&
3)そうでない場合、eが左値であればdecltype(e)がT&であり、これは左値ルールである
4)そうでない場合、decltype(e)はTの例である.
int i = 4;
int arr[5] = {0};
int *ptr = arr;
struct S { double d; } s;
void Overloaded(int);
void Overloaded(char); //
int && RvalRef();
const bool Func(int);
// 1: ,
decltype(arr) var1; // int[5],
decltype(ptr) var2; // int*,
decltype(s.d) var4; // double,
decltype(Overloaded) var5; // ,
// 2: ,
decltype(RvalRef()) var6 = 1; // int&&
// 3: ,
decltype(true ? i : i) var7 = i; // int&, , i
decltype((i)) var8 = i; // int&,
decltype(++i) var9 = i; // int&, ++i i
decltype(arr[3]) var10 = i; // int& []
decltype(*ptr) var11 = i; // int& *
decltype("lval") var12 = "lval"; // const char(&)[9],
// 4: ,
decltype(1) var13; // int,
decltype(i++) var14; // int, i++
decltype((Func(1))) var15; // const bool,
ルール3左値ルールは、確かに判断しにくいので、decltypeで定義された変数を宣言してから、他の文で初期化し、左値が初期化を宣言しなければならない場合は、コンパイラがエラーを報告します.is_を借りることもできますlvalue_referenceなどのテンプレートクラスは変数参照タイプを判断する:#include <type_traits>
#include <iostream>
using namespace std;
int i = 4;
int arr[5] = {0};
int *ptr = arr;
int && RvalRef();
int main(){
cout << is_rvalue_reference<decltype(RvalRef())>::value << endl; // 1
cout << is_lvalue_reference<decltype(true ? i : i)>::value << endl; // 1
cout << is_lvalue_reference<decltype((i))>::value << endl; // 1
cout << is_lvalue_reference<decltype(++i)>::value << endl; // 1
cout << is_lvalue_reference<decltype(arr[3])>::value << endl; // 1
cout << is_lvalue_reference<decltype(*ptr)>::value << endl; // 1
cout << is_lvalue_reference<decltype("lval")>::value << endl; // 1
cout << is_lvalue_reference<decltype(i++)>::value << endl; // 0
cout << is_rvalue_reference<decltype(i++)>::value << endl; // 0
}
decltypeは、decltype(T)&aのdecltype自体が参照であると推定され、後に1つの&が現れると冗長&が現れるなどの冗長シンボルをもたらすことができる.autoは初期化式のcv制限子を持ち去ることはできないが、decltypeは式のcv制限子を持ち去ることができる.#include <type_traits>
#include <iostream>
using namespace std;
const int ic = 0;
volatile int iv;
struct S { int i; };
const S a = {0};
volatile S b;
volatile S* p = &b;
int main() {
cout << is_const<decltype(ic)>::value << endl; // 1
cout << is_volatile<decltype(iv)>::value << endl; // 1
cout << is_const<decltype(a)>::value << endl; // 1
cout << is_volatile<decltype(b)>::value << endl; // 1
cout << is_const<decltype(a.i)>::value << endl; // 0, const // cv
cout << is_volatile<decltype(p->i)>::value << endl; // 0, volatile
}
decltypeの最後の推定結果は、いくつかの冗長シンボルcv制限子と参照を含む&余分なシンボルを無視することができる#include <type_traits>
#include <iostream>
using namespace std;
int i = 1;
int & j = i;
int * p = &i;
const int k = 1;
int main() {
decltype(i) & var1 = i;
decltype(j) & var2 = i; // &,
cout << is_lvalue_reference<decltype(var1)>::value << endl; // 1,
cout << is_rvalue_reference<decltype(var2)>::value << endl; // 0,
cout << is_lvalue_reference<decltype(var2)>::value << endl; // 1,
//decltype(p)* var3 = &i; // //auto* auto , decltype * , int** var3 &i
decltype(p)* var3 = &p; // var3 int**
auto* v3 = p; // v3 int*
v3 = &i;
const decltype(k) var4 = 1; // const,
}
4トレース戻りタイプ
まず、例を見てみましょう.
#include <iostream>
using namespace std;
template<typename T1, typename T2>
auto Sum(const T1 & t1, const T2 & t2) -> decltype(t1 + t2)
{// , auto decltype ,auto , , decltype auto
return t1 + t2;
}
template <typename T1, typename T2>
auto Mul(const T1 & t1, const T2 & t2) -> decltype(t1 * t2)
{
return t1 * t2;
}
int main()
{
auto a = 3;
auto b = 4L;
auto pi = 3.14;
auto c = Mul(Sum(a, b), pi);//
cout << c << endl; // 21.98
}
追踪返回类型用于简化函数定义:#include <type_traits> #include <iostream> using namespace std; // , int (*(*pf())())() {// return nullptr; } // auto (*)() -> int(*) () ( a ) // auto pf1() -> auto (*)() -> int (*)() a auto pf1() -> auto (*)() -> int (*)() {// return nullptr; } int main() { cout << is_same<decltype(pf), decltype(pf1)>::value << endl; // 1 }
トレース戻り値タイプは、転送関数で使用されます.#include <iostream> using namespace std; double foo(int a) { return (double)a + 0.1; } int foo(double b) { return (int)b; } template <class T> auto Forward(T t) -> decltype(foo(t)){// return foo(t); } int main(){ cout << Forward(2) << endl; // 2.1 cout << Forward(0.5) << endl; // 0 }
5 forサイクル
標準ライブラリには既にfor_eachc++11には新しいforループ方式があります.for_each( InputIt first, InputIt last, UnaryFunction f );
#include <vector> #include <iostream> using namespace std; int main() { vector<int> v = {1, 2, 3, 4, 5}; for (auto i = v.begin(); i != v.end(); ++i) cout << *i << endl; // i for (auto e: v)// , , , cout << e << endl; // e }
反復範囲が不確定な場合は、次のように新しいfor形式を使用できません.#include <iostream> using namespace std; int func(int a[]) { for (auto e: a) // , cout << e; } int main() { int arr[] = {1, 2, 3, 4, 5}; func(arr); }