C++自動タイプ推定
7202 ワード
C++言語は、コード書き込みを簡略化するための自動タイプ推定メカニズムを提供しています.これは、
一、auto自動タイプ推定
(1.1)auto変数を値伝達で初期化する
一言でまとめると、オブジェクトのconstと参照属性を捨てて、新しいオブジェクトは新しいコピーのようです.ポインタの場合、最上位constプロパティは破棄され、最下位constプロパティは保持されます.
(1.2)auto変数のポインタまたは参照タイプの初期化
一言でまとめると、参照属性は捨てられますが、const属性は保持されます.ポインタタイプの場合、すべてのconstプロパティが保持されます.
(1.3)auto変数の万能参照初期化
万能参照を参照してください:C++参照の詳細.
二、decltype自動タイプ推定
(2.1)decltype推定変数のタイプ
(2.2)decltype推定式のタイプ
推定変数とは異なり、decltype式の内容が左の場合、参照タイプとして推定されます.
(2.3)decltype推定関数または関数の呼び出し結果
個人的には
(2.4)
(2.4.1)
このテンプレートは通常のコンテナタイプに対応しますが、定数コンテナオブジェクトに対しては操作できません.
エラーの原因は、定数コンテナの場合、
このようにしてこそ、コンパイルを通過することができます.このように偏特化コードを繰り返し書くのは間違いなく面倒だ.しかし、自動タイプ推定を使用すると、簡単になります.
このように、自動タイプ推定により、
(2.4.2)
場合によっては、関数がパラメータ化されたメソッドの戻りタイプに基づいて関数の戻りタイプを決定したい場合があります.これにより、自動タイプ推定を使用できます.
これにより、表示せずに戻りタイプを指定し、foo()メソッドのタイプに応じて戻りタイプを変化させることができる.
三、decltype(auto)タイプ推定(c++14)
一般的なピットは、
auto
とdecltype
を使用して、自動タイプ推定の作業を完了することができ、コンパイル期間中に動作します.これは、実行時にパフォーマンスの損失がないことを示しています.一、auto自動タイプ推定
auto
自動タイプ推定のメカニズムは関数テンプレートの推定メカニズムとよく似ており、auto
はテンプレート内のT
に似ている.(1.1)auto変数を値伝達で初期化する
一言でまとめると、オブジェクトのconstと参照属性を捨てて、新しいオブジェクトは新しいコピーのようです.ポインタの場合、最上位constプロパティは破棄され、最下位constプロパティは保持されます.
int main(int argc, char *argv[])
{
int a = 0;
int &a_ref = a;
const int ca = 0;
const int &ca_ref = ca;
const int *const pa = &a;
int arr[] = {1, 2, 3};
const carr[] = {1, 2, 3};
// 、 。
auto b1 = a; // b1 int, auto int
auto b2 = a_ref; // b2 int, auto int
auto b3 = ca; // b3 int, auto int
auto b4 = ca_ref; // b4 int, auto int
auto b5 = pa; // b5 const int *, auto const int *
auto b6 = arr; // b6 int*, auto int*
auto b7 = carr; // b7 const int*, auto const int*
auto b8 = main; // b8 int(*)(int, char**), auto int(*)(int,char**)
return 0;
}
(1.2)auto変数のポインタまたは参照タイプの初期化
一言でまとめると、参照属性は捨てられますが、const属性は保持されます.ポインタタイプの場合、すべてのconstプロパティが保持されます.
int main(int argc, char *argv[])
{
int a = 0;
int &a_ref = a;
const int ca = 0;
const int &ca_ref = ca;
const int *const pa = &a;
int arr[] = {1, 2, 3};
const int carr[] = {1, 2, 3};
// 、 。
auto &b1 = a; // b1 int&, auto int
auto &b2 = a_ref; // b2 int&, auto int
auto &b3 = ca; // b3 const int&, auto const int
auto &b4 = ca_ref; // b4 const int&, auto const int
auto &b5 = pa; // b5 const int *const &, auto const int *const
auto &b6 = arr; // b6 int*&, auto int*
auto &b7 = carr; // b7 const int *&, auto const int *
auto &b8 = main; // b8 int(&)(int, char**), auto int(int,char**)
return 0;
}
(1.3)auto変数の万能参照初期化
万能参照を参照してください:C++参照の詳細.
二、decltype自動タイプ推定
decltype
は、auto
のように定数および参照を破棄する可能性がないため、auto
よりも穏やかである.式の値で変数を初期化したくなく、式のデータ型を推定したい場合にのみdecltype
を使用します.(2.1)decltype推定変数のタイプ
decltype
推定の方法は非常に簡単です.元のタイプは何ですか.推定の結果は何ですか.int main(int argc, char *argv[])
{
int a = 0;
int &ra = a;
const int &cra = a;
int *pa = &a;
const int *cpa = pa;
const int *const ccpa = pa;
decltype(a) b1 = a; // b1 int
decltype(ra) b2 = a; // b2 int&
decltype(cra) b3 = a;// b3 const int&
decltype(pa) b4 = nullptr; // b4 int*
decltype(cpa) b5 = nullptr; // b5 const int *
decltype(ccpa) b6 = nullptr; // b6 const int *const
return 0;
}
(2.2)decltype推定式のタイプ
推定変数とは異なり、decltype式の内容が左の場合、参照タイプとして推定されます.
int main(int argc, char *argv[])
{
int a = 0;
int *pa = &a;
decltype(1 + 2) b1; // int。
decltype(*pa) b2 = a; // *pa , b int&。
decltype((a)) b3 = a; // (a) , , b int&。
return 0;
}
(2.3)decltype推定関数または関数の呼び出し結果
個人的には
decltype
が最も強力な場所だと思います.この場合、実際に関数を呼び出すのではなく、タイプを推定するだけです(sizeof
と非常に似ています):#include
std::string func() { return std::string(); }
int main(int argc, char *argv[])
{
decltype(func) a; // a :std::string();
decltype(func) *b = nullptr; // b :std::string(*)();
decltype(func) &c = func; // c :std::string(&)();
decltype(func().c_str()) d = nullptr; // d const char *
// func() c_str()。
return 0;
}
(2.4)
decltype
の特殊用法例(2.4.1)
decltype
による変数宣言のコード互換性の向上decltype
を使用すると、テンプレートプログラミングでデータ型のダイナミック効果を実現できます.template
class container_copier
{
public:
typename T::iterator _begin;
typename T::iterator _end;
container_copier(typename T::iterator begin, typename T::iterator end)
: _begin(begin), _end(end) {}
void copy() { /* ... */ }
};
このテンプレートは通常のコンテナタイプに対応しますが、定数コンテナオブジェクトに対しては操作できません.
#include
int main(int argc, char *argv[])
{
std::vector vec = {1, 2, 3, 4, 5};
container_copier<:vector>> cpr1(vec.begin(), vec.end());
cpr1.copy(); // OK.
const std::vector cvec = {1, 2, 3, 4, 5};
container_copier> cpr2(vec.begin(), vec.end()); //
return 0;
}
エラーの原因は、定数コンテナの場合、
begin
関数がconst_を返します.iteratorではなくiteratorです.オートタイプ推定が適用されなければ、偏特化せざるを得ません.template
class container_copier
{
public:
typename T::const_iterator _begin;
typename T::const_iterator _end;
container_copier(typename T::const_iterator begin, typename T::const_iterator end)
: _begin(begin), _end(end) {}
void copy() { /* ... */ }
};
このようにしてこそ、コンパイルを通過することができます.このように偏特化コードを繰り返し書くのは間違いなく面倒だ.しかし、自動タイプ推定を使用すると、簡単になります.
#include
template
class container_copier
{
public:
decltype(T().begin()) _begin;
decltype(T().end()) _end;
container_copier(decltype(T().begin()) begin,
decltype(T().end()) end)
: _begin(begin), _end(end) {}
void copy() { /* ... */ }
};
int main(int argc, char *argv[])
{
std::vector vec = {1, 2, 3, 4, 5};
container_copier<:vector>> cpr1(vec.begin(), vec.end());
cpr1.copy(); // OK.
const std::vector cvec = {1, 2, 3, 4, 5};
container_copier> cpr2(vec.begin(), vec.end()); // OK.
return 0;
}
このように、自動タイプ推定により、
iterator
を使用するか、const_iterator
を使用するかをコンパイラによって動的に決定することができる.(2.4.2)
decltype
を用いて関数戻りタイプの互換性を向上させる場合によっては、関数がパラメータ化されたメソッドの戻りタイプに基づいて関数の戻りタイプを決定したい場合があります.これにより、自動タイプ推定を使用できます.
template
auto func(T&& t) -> decltype(t.foo())
{
// ...
return t.foo();
}
これにより、表示せずに戻りタイプを指定し、foo()メソッドのタイプに応じて戻りタイプを変化させることができる.
三、decltype(auto)タイプ推定(c++14)
decltype(auto)
の意味は、コンパイラが自動的に推定するために自動的に推定する必要があるタイプである.decltype(auto)
を使用する主な目的は、auto
が参照または定数属性を破棄するため、これらの属性を保持するために自動タイプ推定が必要になる場合があるため、decltype
はauto
が破棄した属性を取り戻すことができる.int main(int argc, char *argv[])
{
int a = 0;
const int &a_ref = a;
auto b1 = a_ref; // b1 int
// b1 ?
// :
decltype(auto) b2 = a_ref; // :decltype(a_ref) b2 = a_ref;
// b2 const int &
// :
auto &b3 = a_ref;
return 0;
}
一般的なピットは、
decltype
が左値式を推定すると、参照タイプが生成されます.ただし、ローカル変数の参照を返すと危険です.decltype(auto) func()
{
int i = 30;
// ...
return(i); // , :decltype((i)), i , 。
// return i; 。
}