テンプレート<unsigned int N>はどういう意味ですか?


121

テンプレートを宣言するとき、次のようなコードに慣れています。

template <class T>

しかし、この質問では、彼らは以下を使用しました:

template <unsigned int N>

コンパイルできることを確認しました。しかし、それはどういう意味ですか?非型パラメーターですか?もしそうなら、どのようにして型パラメーターのないテンプレートを作成できますか?

回答:


147

型ではなく整数でクラスをテンプレート化することは完全に可能です。テンプレート化された値を変数に割り当てるか、他の整数リテラルと同じように操作できます。

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
}

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;
bobobobo

@boboboboこれはC ++ 11およびの前に回答されましたconstexpr
Justin Meiners、2018年

153

はい、それは非型パラメーターです。あなたはいくつかの種類のテンプレートパラメータを持つことができます

  • タイプパラメータ。
    • タイプ
    • テンプレート(クラスとエイリアステンプレートのみ、関数または変数テンプレートなし)
  • 非型パラメーター
    • ポインタ
    • 参考文献
    • 積分定数式

あなたが持っているものは最後の種類のものです。これはコンパイル時定数(いわゆる定数式)であり、整数型または列挙型です。標準で調べた後、テンプレートがタイプではなくても、クラステンプレートをタイプセクションに移動する必要がありました。ただし、これらの種類を説明することを目的として、タイプパラメータと呼ばれます。ポインター(およびメンバーポインター)と、外部リンケージ(他のオブジェクトファイルからリンクでき、プログラム全体で一意のアドレスを持つオブジェクト)への参照を設定できます。例:

テンプレートタイプパラメータ:

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
};

ヨハネス、テンプレートは「タイプ」の下にファイルされていますか?私はそれらがどんなタイプから作られることができるのかと思ったが、タイプ自体ではなかったのか?
sbi 2010

@sbiは説明を参照してください。「テンプレートをタイプではない場合でも、標準で調べた後、クラステンプレートをタイプセクションに移動する必要がありました。しかし、これらのタイプを説明する目的で、タイプパラメータと呼ばれています。 」14.1 / 2の脚注126はそう言っています。これは、非型パラメーターを値/参照を宣言するものにするために行われた分類であり、型パラメーターは型名またはテンプレート名を宣言するものです。
Johannes Schaub-litb 2010

@ JohannesSchaub-litbなので、テンプレートをタイプする方法はありませんstd :: string?さまざまな文字列ごとに一意のIDを作成するために静的カウンタを含むtemplate <std :: string S>クラスのように 文字列をintにハッシュすることは残念ながら正しい唯一の方法でしょうか?
relaxxx

1
この回答がテンプレートクラスメンバーオブジェクト、つまりtemplate <typename C、typename R、typename P1、typename P2>で完成するのを見てみたいです。structmystruct <R(C :: *)(P1、P2)>
Johnny Pauling

を含むコードはSillyExample、GCC 4.8.4ではコンパイルできません。最初のエラーはthe value of ‘flag’ is not usable in a constant expressionです。他にもエラーがあります
HEKTO

17

「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.
 }

15

テンプレートクラスはマクロのようなもので、邪悪なことはほとんどありません。

テンプレートをマクロと考えてください。テンプレートを使用してクラス(または関数)を定義すると、テンプレートへのパラメーターがクラス(または関数)定義に代入されます。

違いは、パラメータには「タイプ」があり、渡された値は、関数へのパラメータと同様に、コンパイル時にチェックされることです。有効な型は、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億倍の安全性と柔軟性を備えています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.