回答:
型ではなく整数でクラスをテンプレート化することは完全に可能です。テンプレート化された値を変数に割り当てるか、他の整数リテラルと同じように操作できます。
unsigned int x = N;
実際、コンパイル時に評価するアルゴリズムを作成できます(Wikipediaから):
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
int x = Factorial<4>::value; // == 24
int y = Factorial<0>::value; // == 1
}
constexpr
。
はい、それは非型パラメーターです。あなたはいくつかの種類のテンプレートパラメータを持つことができます
あなたが持っているものは最後の種類のものです。これはコンパイル時定数(いわゆる定数式)であり、整数型または列挙型です。標準で調べた後、テンプレートがタイプではなくても、クラステンプレートをタイプセクションに移動する必要がありました。ただし、これらの種類を説明することを目的として、タイプパラメータと呼ばれます。ポインター(およびメンバーポインター)と、外部リンケージ(他のオブジェクトファイルからリンクでき、プログラム全体で一意のアドレスを持つオブジェクト)への参照を設定できます。例:
テンプレートタイプパラメータ:
template<typename T>
struct Container {
T t;
};
// pass type "long" as argument.
Container<long> test;
テンプレート整数パラメーター:
template<unsigned int S>
struct Vector {
unsigned char bytes[S];
};
// pass 3 as argument.
Vector<3> test;
テンプレートポインターパラメーター(ポインターを関数に渡す)
template<void (*F)()>
struct FunctionWrapper {
static void call_it() { F(); }
};
// pass address of function do_it as argument.
void do_it() { }
FunctionWrapper<&do_it> test;
テンプレート参照パラメーター(整数を渡す)
template<int &A>
struct SillyExample {
static void do_it() { A = 10; }
};
// pass flag as argument
int flag;
SillyExample<flag> test;
テンプレートテンプレートパラメータ。
template<template<typename T> class AllocatePolicy>
struct Pool {
void allocate(size_t n) {
int *p = AllocatePolicy<int>::allocate(n);
}
};
// pass the template "allocator" as argument.
template<typename T>
struct allocator { static T * allocate(size_t n) { return 0; } };
Pool<allocator> test;
パラメータのないテンプレートは使用できません。しかし、明示的な引数のないテンプレートも可能です-デフォルトの引数があります:
template<unsigned int SIZE = 3>
struct Vector {
unsigned char buffer[SIZE];
};
Vector<> test;
構文的にtemplate<>
は、パラメータのないテンプレートではなく、明示的なテンプレート特殊化をマークするために予約されています。
template<>
struct Vector<3> {
// alternative definition for SIZE == 3
};
SillyExample
、GCC 4.8.4ではコンパイルできません。最初のエラーはthe value of ‘flag’ is not usable in a constant expression
です。他にもエラーがあります
「unsigned int」に基づいてクラスをテンプレート化します。
例:
template <unsigned int N>
class MyArray
{
public:
private:
double data[N]; // Use N as the size of the array
};
int main()
{
MyArray<2> a1;
MyArray<2> a2;
MyArray<4> b1;
a1 = a2; // OK The arrays are the same size.
a1 = b1; // FAIL because the size of the array is part of the
// template and thus the type, a1 and b1 are different types.
// Thus this is a COMPILE time failure.
}
テンプレートクラスはマクロのようなもので、邪悪なことはほとんどありません。
テンプレートをマクロと考えてください。テンプレートを使用してクラス(または関数)を定義すると、テンプレートへのパラメーターがクラス(または関数)定義に代入されます。
違いは、パラメータには「タイプ」があり、渡された値は、関数へのパラメータと同様に、コンパイル時にチェックされることです。有効な型は、intやcharなどの通常のC ++型です。テンプレートクラスをインスタンス化するときは、指定した型の値を渡します。テンプレートクラス定義の新しいコピーでは、この値は、パラメーター名が元の定義にあった場所に置き換えられます。ちょうどマクロのようです。
パラメータには " class
"または " typename
"タイプを使用することもできます(実際には同じです)。これらのタイプのいずれかのパラメーターを使用すると、値の代わりにタイプ名を渡すことができます。以前と同様に、パラメーター名がテンプレートクラス定義内にあったすべての場所で、新しいインスタンスを作成するとすぐに、渡した型になります。これは、テンプレートクラスの最も一般的な使用法です。C ++テンプレートについて何か知っている人なら誰でも、その方法を知っています。
次のテンプレートクラスのサンプルコードを考えてみます。
#include <cstdio>
template <int I>
class foo
{
void print()
{
printf("%i", I);
}
};
int main()
{
foo<26> f;
f.print();
return 0;
}
機能的には、このマクロを使用するコードと同じです。
#include <cstdio>
#define MAKE_A_FOO(I) class foo_##I \
{ \
void print() \
{ \
printf("%i", I); \
} \
};
MAKE_A_FOO(26)
int main()
{
foo_26 f;
f.print();
return 0;
}
もちろん、テンプレートバージョンは10億倍の安全性と柔軟性を備えています。
static constexpr int
代わりにtype を使用することもできますenum
。したがって、Factorial<0>
テンプレートはを持ちstatic constexpr int value = 1
、持つtemplate <int N> struct Factorial
ことができますstatic constexpr int value = N * Factorial<N - 1>::value;