最終更新日時(UTC):
が更新

履歴 編集

非型テンプレートパラメータのauto宣言(C++17)

概要

C++14まで、以下のように書いていた「指定された型の定数を受け取る」意図の非型テンプレートパラメータ(non-type template parameter)だが、

template <class T, T V>
struct X;

X<int, 3>;

C++17ではこの用途のためのシンタックスシュガー(糖衣構文、syntactic sugar)が導入され、テンプレートパラメータをautoにして値を受け取ることができるようになった。

template <auto X>
struct A {};

A<3>;    // OK
A<true>; // OK
A<'a'>;  // OK
A<3.14>; // コンパイルエラー (浮動小数点数は渡せない)

テンプレートの中では、decltypeを使用すればXの型を取得できる。

このautoは、変数宣言のautoと同じくプレースホルダーという扱いになる。そのため、template <auto* P>template <auto& R>のような推論補助もできる。また、autoの代わりにdecltype(auto)を使うこともできる。

仕様

n4659 [temp.param]/4より

型ではないテンプレートパラメータは、次の型(cv 修飾されていてもかまわない)のうちの1つを持たなければならない:

  • 整数型または列挙型
  • オブジェクトへのポインタまたは関数へのポインタ
  • オブジェクトへの左辺値参照または関数への左辺値参照
  • メンバへのポインタ
  • std::nullptr_t
  • プレースホルダタイプを含む型 <-- この行が追加された

なお、[temp.param]/4 は C++20 で変更予定である。Working Draft, Standardを参照。

この他にも変更点が多くある。P0127R2 Declaring non-type template arguments with autoを参照。

#include <type_traits>

template <auto* X>
struct A {
  using type = decltype(X);
};

int main()
{
  constexpr int* p = nullptr;
  static_assert(std::is_same<A<p>::type, int*>{});
}

出力

この機能が必要になった背景・経緯

以下、P0127R1 Declaring non-type template arguments with autoより引用した。

この提案では、autoプレースホルダ型指定子を使用して型でないテンプレートパラメータを宣言できるようにすることを提案する。望ましい効果は、同様の構文が総称ラムダに対して機能するのと同じように、対応する型ではないテンプレート引数の型が自動的に推定されることである。

現在、型ではないテンプレートパラメータの型を明示的に指定しなければならない。これは、任意の型の定数引数を取ることを意図したテンプレートを書くときに不必要な冗長性と柔軟性の低下を招く。

template <typename T, T v> struct S { };    // 定義
S<decltype(x), x> s;                    // インスタンス化

この例では、decltypeを使用して、xの型と値の両方をSに渡す前に、xの型(コンパイル時定数)を取得する。目的は、xの型を別のテンプレート引数として渡す必要がないようにSの宣言を変更できるようにすることである。これにより、次のようなより簡単なインスタンス化が可能になる。

S<x> s; // desired instantiation 

これは、テンプレートパラメータリストでautoキーワードを使用できるようにすることで実現できる。

template <auto v> struct S; // type of v is deduced

関連項目

参照