代码之家  ›  专栏  ›  技术社区  ›  Baruch

c++非类型模板值的用途是什么?

  •  2
  • Baruch  · 技术社区  · 14 年前

    c++非类型模板值的用途是什么?怎么办:

    template <int I>
    class MyClass
    {
    public:
        MyClass();
        .
        . //Use I;
        .
    }
    

    这是做不到的:

    class MyClass
    {
        int I;
    public:
        MyClass(int i) : I(i) {}
        .
        . //Use I
        .
    }
    

    在我看来,模板版本会造成编译器创建两种不同类型的对象时不必要的开销,每个类方法都有不同的副本。

    9 回复  |  直到 14 年前
        1
  •  6
  •   Dialecticus    14 年前

    使用模板可以执行以下操作:

    template <int I>
    class MyClass
    {
       int array[I];
    }
    
        2
  •  8
  •   Steve Jessop    14 年前

    一个用途是模板参数推导可以用来计算I,省去了程序员的麻烦:

    template<typename T, size_t N>
    T *end(T (&ra)[N]) {
        return ra + N;
    }
    
    int main() {
        std::string headings[] = {"name", "dob", "address"};
        std::ostream_iterator<std::string> output(std::cout, "\t")
        std::copy(headings, end(headings), output);
        // or
        std::vector<std::string> headingvec(headings, end(headings));
    
    }
    

    别乱来 sizeof 每次你想用数组的时候。

    我敢肯定,它的最初动机是类模板,比如 std::bitset 不过,正如其他人所说。

        3
  •  3
  •   Evan Teran    14 年前

    单独类型的创建实际上是一个有用的idom(google“int-to-type习惯用法”)。但除此之外,模板版本允许编译人员在编译时而不是运行时知道数字的值。这意味着有一组不同的可能的优化是可用的。实际上,可能性是巨大的,这个特性基本上使c++模板本身成为一种完整的计算语言。

    对于常见用法的一个基本示例,假设您希望在编译时使具有固定大小的容器为已知。如果没有非类型模板参数,则无法实现此功能。像这样的:

    array<int, 10> x; // create an object 10 int's big
    
        4
  •  2
  •   Edward Strange    14 年前

    这样的构造可以使用的东西是无穷的。一个基本的例子是boost::array,它通过一个非类型模板参数指定它的大小。不可能以任何其他方式(聚合类型、堆栈上的内容)执行相同的操作。

        5
  •  2
  •   tdammers    14 年前

    区别在于模板版本在编译时得到扩展,因此整数编译成隐式常量;在非模板版本中,在运行时仍然存在整数。在模板版本中, MyClass<1> MyClass<2> 是两种不同的、不兼容的类型,尝试将一种类型分配给另一种类型将产生编译器错误。

    典型的例子是一个通用向量类(数学向量,而不是 std::vector )无论向量的维数是多少,大多数方法都是相同的(添加2-空间向量和4-空间向量是完全相同的操作),但有些方法仅在特殊情况下定义(交叉积仅在3-空间和7-空间向量上定义)。如果要将向量的维度存储在成员变量中,则每次需要使用可能不兼容的参数执行操作时(例如,向4空间向量添加2空间向量),都必须执行运行时检查,并且必须在运行时处理产生的错误。

        6
  •  2
  •   redeye    14 年前

    使用非类型模板参数,您真的可以做很多事情。一个这样的例子,通常与模板元编程有关(参见Andrei Alexandrescu的关于这个问题的书:“现代C++设计”)是一个模板类,它在编译时计算阶乘。有点像

    template<int N>
    class factorial
    {
     public:
         enum { value = N * factorial<N-1>::value };
    }
    

    然后,您可以完全专门化您的阶乘类0,因此它实际上在某个地方结束:

    template<>
    class factorial<0>
    {
     public:
         enum { value = 1 };
    }
    

    然后,可以使用此类在编译时计算一些阶乘,如下所示:

    int f4 = factorial<4>::value; // f4 will be 24 at compile time. Neat!
    

    这也许不是最有用的例子,但你可以理解。

    你可以在维基百科上找到这个例子,在那里你也可以阅读更多关于这个主题的内容。

    干杯。

        7
  •  1
  •   John Dibling    14 年前

    一个用途是 metaprogramming .

    一个例子(不知羞耻地从维基百科上偷走)是一个模板,它在编译时计算一个数字的威力:

    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
    }
    
        8
  •  0
  •   Nim    14 年前

    如果你想为类型定义“常量”,这很有用。。。

    例如。。

    template <typename _foo, int _id>
    class field
    {
    public:
    
      int id() { return _id; }
    
    };
    

    现在当你声明一个字段的实例时,你可以对它的id进行编码。。。

    field<int, 10> _f1;
    field<double, 11> _f2;
    

    为什么这有用?考虑第三方使用的协议,例如交换(比如FAST/FIX等)

        9
  •  0
  •   Matthieu M.    14 年前

    举例说明。

    目前,我正在研究一个Trie结构(顺便说一句,如果有人知道一个好的实现……)。

    Trie基本上是一个N元树,第一级基本上是完整的,然后越深入,越稀疏(这不是结构的适当性,只是大多数字典的短词比长词多得多)。

    我正在考虑使用这个模板特性来最小化分配的节点数。以一种非模板化的方式:

    class Node3; // contains N Node2
    class Node2; // contains N Node1
    class Node1; // contains N Node0
    class Node0; // contains N Node
    class Node;  // contains N POINTERS to Node
    

    使用模板我可以:

    template <size_t L> class Node; // contains N Node<L-1>
    template <> class Node<0>;      // contains N Node
    class Node;                     // contains N POINTERS to Node
    

    省去了编写宏或一遍又一遍地复制代码的枯燥任务。