2009-01-31 6 views
85

Khi tuyên bố một mẫu, tôi đã quen với việc có loại mã này:Mẫu <unsigned int N> có nghĩa là gì?

template <class T> 

Nhưng in this question, họ đã sử dụng:

template <unsigned int N> 

Tôi đã kiểm tra rằng nó biên dịch. Nhưng nó có nghĩa gì? Nó là một tham số không phải kiểu? Và nếu có, làm thế nào chúng ta có thể có một mẫu mà không có bất kỳ tham số kiểu nào?

Trả lời

116

Hoàn toàn có thể tạo mẫu cho một lớp trên một số nguyên chứ không phải là một loại. Chúng ta có thể gán giá trị templated cho một biến, hoặc sửa đổi nó theo một cách chúng ta có thể với bất kỳ số nguyên khác theo nghĩa đen:

unsigned int x = N; 

Trong thực tế, chúng ta có thể tạo ra các thuật toán mà đánh giá tại thời gian biên dịch (từ 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 
} 
+1

Bạn cũng có thể sử dụng loại 'static constexpr int' thay vì' enum'. Vì vậy, mẫu 'Factorial <0>' sẽ có 'static constexpr int value = 1' và' template struct Factorial' có thể có 'static constexpr int value = N * Factorial :: value;' – bobobobo

14

Bạn templatize lớp học của mình dựa trên 'int không dấu'.

Ví dụ:

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

Vâng, đó là một tham số không kiểu. Bạn có thể có một số loại thông số mẫu

  • Tham số loại.
    • loại
    • Templates (chỉ các lớp học và các mẫu bí danh, không có chức năng hoặc các mẫu biến)
  • Non-type Parameters
    • Pointers
    • Tài liệu tham khảo
    • Integral biểu thức hằng số

Những gì bạn có ở đây là loại cuối cùng. Đó là hằng số thời gian biên dịch (được gọi là biểu thức hằng số) và là kiểu số nguyên hoặc kiểu liệt kê. Sau khi tìm kiếm nó trong tiêu chuẩn, tôi đã phải di chuyển các mẫu lớp lên vào phần loại - mặc dù các mẫu không phải là loại. Tuy nhiên, chúng được gọi là kiểu tham số cho mục đích mô tả những loại đó. Bạn có thể có con trỏ (và cũng là con trỏ thành viên) và tham chiếu đến các đối tượng/hàm có liên kết bên ngoài (những liên kết có thể được liên kết từ các tệp đối tượng khác và địa chỉ của nó là duy nhất trong toàn bộ chương trình).Ví dụ:

Template loại tham số:

template<typename T> 
struct Container { 
    T t; 
}; 

// pass type "long" as argument. 
Container<long> test; 

Mẫu số nguyên tham số:

template<unsigned int S> 
struct Vector { 
    unsigned char bytes[S]; 
}; 

// pass 3 as argument. 
Vector<3> test; 

tham số con trỏ Template (đi qua một con trỏ tới một hàm)

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; 

tham số mẫu tham khảo (chuyển số nguyên)

template<int &A> 
struct SillyExample { 
    static void do_it() { A = 10; } 
}; 

// pass flag as argument 
int flag; 
SillyExample<flag> test; 

Tham số mẫu mẫu.

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; 

Mẫu không có tham số nào là không thể. Tuy nhiên, một mẫu mà không cần bất kỳ lý lẽ rõ ràng là có thể - nó có đối số mặc định:

template<unsigned int SIZE = 3> 
struct Vector { 
    unsigned char buffer[SIZE]; 
}; 

Vector<> test; 

Cú pháp, template<> được dành riêng để đánh dấu một mẫu chuyên môn rõ ràng, thay vì một mẫu không có tham số:

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

Johannes, là các mẫu được đệ trình dưới " loại "? Tôi nghĩ rằng họ là những loại có thể được làm từ, nhưng không phải loại của mình? – sbi

+0

@sbi xem giải thích: "Sau khi tìm kiếm nó trong tiêu chuẩn, tôi đã phải di chuyển các mẫu lớp lên vào phần loại - mặc dù mẫu không phải là loại. Nhưng chúng được gọi là loại tham số cho mục đích mô tả các loại đó dù sao ". Chú thích chân trang 126 trên 14.1/2 nói như vậy. Nó chỉ là một phân loại được thực hiện để làm cho các tham số không gõ một cái gì đó tuyên bố một giá trị/tham chiếu và kiểu-tham số là một cái gì đó tuyên bố một tên loại hoặc tên mẫu. –

+0

@ JohannesSchaub-litb vì vậy không có cách nào để nhập mẫu với giả sử std :: string? giống như template class với một số counter tĩnh trong nó để tạo id duy nhất cho mỗi chuỗi khác nhau? băm chuỗi để int sẽ là cách duy nhất không may phải không? – relaxxx

12

Mẫu lớp học giống như một vĩ mô, chỉ có một toàn bộ rất ít ác.

Hãy nghĩ mẫu là macro. Các tham số cho mẫu được thay thế thành định nghĩa lớp (hoặc hàm), khi bạn định nghĩa một lớp (hoặc hàm) bằng cách sử dụng một khuôn mẫu.

Sự khác biệt là các tham số có "loại" và giá trị được truyền được kiểm tra trong quá trình biên dịch, như tham số cho hàm. Các loại hợp lệ là các loại C++ thông thường của bạn, như int và char. Khi bạn khởi tạo một lớp mẫu, bạn chuyển một giá trị kiểu mà bạn đã chỉ định, và trong một bản sao mới của định nghĩa lớp mẫu, giá trị này được thay thế ở bất cứ nơi nào tên tham số nằm trong định nghĩa gốc. Giống như một macro.

Bạn cũng có thể sử dụng loại "class" hoặc "typename" cho thông số (chúng thực sự giống nhau). Với tham số của một trong các loại này, bạn có thể chuyển tên loại thay vì giá trị. Cũng giống như trước đây, ở khắp mọi nơi tên tham số nằm trong định nghĩa lớp mẫu, ngay sau khi bạn tạo một cá thể mới, trở thành bất kỳ kiểu nào bạn vượt qua. Đây là cách sử dụng phổ biến nhất cho một lớp mẫu; Mọi người đều biết bất cứ điều gì về các mẫu C++ đều biết cách làm điều này.

Xem xét việc này mẫu mã lớp Ví dụ:

#include <cstdio> 
template <int I> 
class foo 
{ 
    void print() 
    { 
    printf("%i", I); 
    } 
}; 

int main() 
{ 
    foo<26> f; 
    f.print(); 
    return 0; 
}

Đó là chức năng giống như mã này vĩ mô sử dụng:

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

Tất nhiên, phiên bản mẫu là một tỷ lần an toàn hơn và linh hoạt hơn .