【问题标题】:What does template <unsigned int N> mean?模板 <unsigned int N> 是什么意思?
【发布时间】:2010-10-04 16:30:48
【问题描述】:

在声明模板时,我习惯了这种代码:

template <class T>

但是in this question,他们使用了:

template <unsigned int N>

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

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    是的,它是一个非类型参数。你可以有几种模板参数

    • 类型参数。
      • 类型
      • 模板(只有类和别名模板,没有函数或变量模板)
    • 非类型参数
      • 指针
      • 参考文献
      • 整型常量表达式

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

    模板类型参数:

    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&lt;&gt; 保留用于标记显式模板特化,而不是没有参数的模板:

    template<>
    struct Vector<3> {
        // alternative definition for SIZE == 3
    };
    

    【讨论】:

    • Johannes,模板是否归档在“类型”下?我认为它们是可以制成的类型,但不是类型本身?
    • @sbi 查看解释:“在标准中查找后,我不得不将类模板移到类型部分 - 即使模板不是类型。但它们被称为类型参数尽管如此,描述这些类型的目的。”。 14.1/2 的脚注 126 这么说。它只是一种分类,使非类型参数成为声明值/引用的东西,而类型参数成为声明类型名称或模板名称的东西。
    • @JohannesSchaub-litb 所以没有办法用 std::string 输入模板?像 template<:string s> 类,里面有一些静态计数器来为每个不同的字符串创建唯一的 id?不幸的是,将字符串散列到 int 是唯一的方法吗?
    • 我很想看到这个答案用模板类成员对象完成,即 template struct mystruct
    • 带有SillyExample的代码段不能被GCC 4.8.4编译。第一个错误是the value of ‘flag’ is not usable in a constant expression。还有其他错误
    【解决方案2】:

    完全可以在整数而不是类型上对类进行模板化。我们可以将模板化的值分配给一个变量,或者以我们可能使用任何其他整数文字的方式对其进行操作:

    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
    }
    

    【讨论】:

    • 您也可以使用static constexpr int 类型来代替您的enum。所以Factorial&lt;0&gt; 模板会有static constexpr int value = 1,而template &lt;int N&gt; struct Factorial 可以有static constexpr int value = N * Factorial&lt;N - 1&gt;::value;
    • @bobobobo 这是在 C++11 和 constexpr 之前回答的。
    • 使用枚举作为参数时出错。 。 enum 的可能值是有限的,有什么办法让它起作用。
    • @JustinMeiners 如果您发布一个“重复的问题”并期望得到不是 30 年前的答案,那么同样的推理就不会被应用......而且该评论对我很有用。
    【解决方案3】:

    您根据“无符号整数”模板化您的类。

    例子:

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

    【讨论】:

      【解决方案4】:

      模板类就像一个宏,只是少了很多邪恶。

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

      不同之处在于参数具有“类型”,并且在编译期间会检查传递的值,就像函数的参数一样。有效的类型是您的常规 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;
      }

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

      【讨论】:

        猜你喜欢
        • 2020-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-07
        • 1970-01-01
        • 2015-08-28
        • 2011-06-05
        • 2010-09-29
        相关资源
        最近更新 更多