LoginSignup
1
5

More than 3 years have passed since last update.

テンプレートの型推論についてメモしておく

Last updated at Posted at 2019-02-11

はじめに

いつものパターンでテンプレートの型推論について何回も忘れるのでメモする。
参考書籍はEffective Modern C++

パターン分け

テンプレートの型推論について、下記関数テンプレートの擬似コードを用いて3パターンに分類。

template<typename T>
void f(ParamType param);

f(expr); // 実引数exprからTとParamTypeを推論
  1. ParamTypeが参照 or ポインタ (ユニバーサル参照ではない)
  2. ParamTypeがユニバーサル参照
  3. ParamTypeが参照でもポインタでもない

パターン1: ParamTypeが参照 or ポインタ (ユニバーサル参照ではない)

下記条件に従って推論する。

  1. exprの参照性は無視される
  2. exprの型をParamTypeとパターンマッチングし、Tを決定
template<typename T>
void f(T& param); // ParamType: T&

int x = 27;
const int cx = x;
const int& rx = x;

f(x);  // f(int& param)      : Tはint
f(cx); // f(const int& param): Tはconst int
f(rx); // f(const int& param): Tはconst int
template<typename T>
void f(const T& param); // ParamType: const T&

int x = 27;
const int cx = x;
const int& rx = x;

f(x);  // f(const int& param): Tはint
f(cx); // f(const int& param): Tはint
f(rx); // f(const int& param): Tはint
template<typename T>
void f(T* param); // ParamType: T*

int x = 27;
const int* px = &x;

f(&x); // f(int* param)      : Tはint
f(px); // f(const int* param): Tはconst int

パターン2: ParamTypがユニバーサル参照

下記条件に従って推論する。

  1. exprが左辺値の場合、TもParamTypeは左辺値参照と推論
  2. exprが右辺値の場合、パターン1の規則を適用
template<typename T>
void f(T&& param); // ParamType: T&&

int x = 27;
const int cx = x;
const int& rx = x;

f(x);  // f(int& && param) -> f(int& param): 参照の圧縮
       // f(int& param)      : Tはint&

f(cx); // f(const int& && param) -> f(const int& param): 参照の圧縮
       // f(const int& param): Tはconst int&

f(rx); // f(const int& && param) -> f(const int& param): 参照の圧縮
       // f(const int& param): Tはconst int&

f(27); // f(int&& param): Tはint

パターン3: ParamTypeが参照でもポインタでもない

下記条件に従って推論する。

  1. exprの参照性は無視される
  2. cv型修飾子(const, volatile)も無視される
template<typename T>
void f(T param); // ParamType: T

int x = 27;
const int cx = x;
const int& rx = x;

f(x);  // f(int param): Tはint
f(cx); // f(int param): Tはint (paramは実引数のコピーなのでconstは付かない)
f(rx); // f(int param): Tはint

const char* const ptr = "const pointer";
f(ptr); // f(const char* param): Tはconst char*

実引数が配列の場合はポインタに成り下がる(decay)ので注意。

template<typename T>
void f(T param); // ParamType: T

const char ary[] = "char array";
f(ary); // f(const char* param): Tはconst char*

ただし、ParamTypeが参照の場合は成り下がらない。

template<typename T>
void f(T& param); // ParamType: T

const char ary[] = "char array";
f(ary); // f(const char (&)[11] param): Tはconst char [11]
1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5