C++
template
C++11
型推論
EffectiveModernC++

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


はじめに

いつものパターンでテンプレートの型推論について何回も忘れるのでメモする。

参考書籍は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はconst int
f(cx); // f(const int& param): Tはconst int
f(rx); // f(const int& param): Tはconst 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 (&)[10] param): Tはconst char (&)[10]