模板<unsigned int N>是什么意思?


121

在声明模板时,我习惯于使用这种代码:

template <class T>

但是在这个问题上,他们使用了:

template <unsigned int N>

我检查它是否可以编译。但是这是什么意思?它是非类型参数吗?如果是这样,我们如何有一个没有任何类型参数的模板?

Answers:


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
您也可以使用type static constexpr int代替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
贾斯汀·迈纳斯

154

是的,它是非类型参数。您可以具有多种模板参数

  • 类型参数。
    • 种类
    • 模板(仅类和别名模板,无函数或变量模板)
  • 非类型参数
    • 指针
    • 参考资料
    • 整数常量表达式

您所拥有的是最后一种。它是一个编译时常量(所谓的常量表达式),类型为整数或枚举。在标准中查找之后,我不得不将类模板移到“类型”部分中-即使模板不是类型。但是出于描述这些种类的目的,它们被称为类型参数。您可以拥有具有外部链接的对象/函数的指针(以及成员指针)和引用(可以从其他对象文件链接到这些对象/函数,并且其地址在整个程序中是唯一的)。例子:

模板类型参数:

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

约翰尼斯,模板是否归类于“类型”下?我以为它们是什么类型的,但不是类型本身?
2010年

@sbi看到了解释:“在标准中查找之后,我不得不将类模板移至类型部分-即使模板不是类型。但是出于描述这些类型的目的,它们被称为类型参数。 ”。14.1 / 2上的脚注126就是这样。它只是一种分类,使非类型参数成为声明值/引用的类型,而类型参数成为声明类型名或模板名称的类型。
Johannes Schaub-litb 2010年

@ JohannesSchaub-litb,所以没有办法让模板说std :: string吗?像template <std :: string S>类,其中带有一些静态计数器,可为每个不同的字符串创建唯一的ID?不幸的是,将字符串哈希为int是唯一的方法吗?
Relaxxx 2012年

1
我很乐意看到此答案已通过模板类成员对象完成,例如template <typename C,typename R,typename P1,typename P2> struct mystruct <R(C :: *)(P1,P2)>
Johnny Pauling

带有SillyExampleGCC 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

模板类就像一个宏,只有很少的邪恶。

将模板视为宏。使用模板定义类(或函数)时,模板的参数将替换为类(或函数)定义。

不同之处在于参数具有“类型”,并且在编译期间检查传递的值,就像函数的参数一样。有效的类型是常规C ++类型,例如int和char。实例化模板类时,将传递您指定的类型的值,并且在模板类定义的新副本中,该值将替换为原始定义中参数名称的任何位置。就像宏一样。

您也可以使用“ 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;
}

当然,模板版本更安全,更灵活十亿倍。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.