Thông số mẫu không phải loại


93

Tôi hiểu rằng tham số mẫu không phải kiểu phải là một biểu thức tích phân không đổi. Ai đó có thể làm sáng tỏ lý do tại sao nó như vậy?

template <std::string temp>
void foo()
{
     // ...
}
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'.

Tôi hiểu biểu thức tích phân không đổi là gì. Lý do gì không cho phép các loại không phải hằng số std::stringnhư trong đoạn mã trên?


17
Một tham số mẫu được giải quyết tại thời điểm biên dịch.
Etienne de Martel

Câu trả lời:


121

Lý do bạn không thể làm điều này là vì các biểu thức không phải hằng số không thể được phân tích cú pháp và thay thế trong thời gian biên dịch. Chúng có thể thay đổi trong thời gian chạy, điều này sẽ yêu cầu tạo một mẫu mới trong thời gian chạy, điều này không thể thực hiện được vì mẫu là một khái niệm thời gian biên dịch.

Đây là những gì tiêu chuẩn cho phép đối với các tham số mẫu không phải kiểu (14.1 [temp.param] p4):

Tham số mẫu không phải kiểu phải có một trong các kiểu sau (tùy chọn đủ điều kiện cv):

  • kiểu tích phân hoặc kiểu liệt kê,
  • con trỏ tới đối tượng hoặc con trỏ tới hàm,
  • tham chiếu giá trị đến đối tượng hoặc tham chiếu giá trị đến hàm,
  • con trỏ tới thành viên,
  • std::nullptr_t.

6
@ALOToverflow: Điều đó nằm trong "con trỏ tới thành viên". Đó là "con trỏ tới chức năng thành viên" hoặc "con trỏ tới dữ liệu thành viên".
Xeo

4
Cần lưu ý rằng đối với trường hợp con trỏ đến các đối tượng (hoặc trường cá thể), các đối tượng phải có thời lượng lưu trữ tĩnh và liên kết (bên ngoài trước C ++ 11, bên trong hoặc bên ngoài trong C ++ 11), để con trỏ đến chúng có thể được tạo tại thời điểm biên dịch.
Theodore Murdock

2
Trong C ++ 20, điều này hiện được cho phép với điều kiện là kiểu có cấu trúc bình đẳng mạnh mẽ, là một subobjects theo nghĩa đen, không thể thay đổi / dễ bay hơi và ở đó toán tử tàu vũ trụ là công khai.
Rakete1111

73

Điều đó không được phép.

Tuy nhiên, điều này được cho phép:

template <std::string * temp> //pointer to object
void f();

template <std::string & temp> //reference to object
void g();

Xem §14.1 / 6,7,8 trong Tiêu chuẩn C ++ (2003).


Hình minh họa:

template <std::string * temp> //pointer to object
void f()
{
   cout << *temp << endl;
}

template <std::string & temp> //reference to object
void g()
{
     cout << temp << endl;
     temp += "...appended some string";
}

std::string s; //must not be local as it must have external linkage!

int main() {
        s = "can assign values locally";
        f<&s>();
        g<s>();
        cout << s << endl;
        return 0;
}

Đầu ra:

can assign values locally
can assign values locally
can assign values locally...appended some string

7
@Mahesh: Bởi vì cái mà mẫu về cơ bản là địa chỉ của std::stringcon trỏ hoặc đối tượng tham chiếu đó. Nếu biến đó là cục bộ, bạn có thể nhận được các địa chỉ khác nhau mỗi khi hàm được gọi.
Xeo

11
@Mahesh: Bạn không biết ngăn xếp cuộc gọi trông như thế nào tại thời điểm biên dịch. Trước hàm của bạn, có thể có 10 hàm khác hoặc 3 hàm khác hoặc nhiều hàm khác, vì vậy địa chỉ trên ngăn xếp, nơi chuỗi được tạo có thể thay đổi từ lệnh gọi này sang lệnh gọi khác. Khi bạn có một đối tượng có liên kết bên ngoài, địa chỉ của nó sẽ được cố định trong quá trình biên dịch / liên kết.
Xeo

2
@Xeo " địa chỉ của nó được cố định trong quá trình biên dịch / liên kết. " Hoặc không, đối với mã có thể di dời hoặc độc lập với vị trí.
tò mò

1
Câu trả lời này (hiện tại) dường như không giải quyết được câu hỏi của OP, đó là hỏi tại sao hành vi này tồn tại; câu trả lời này chỉ trình bày lại ví dụ của OP mà không đưa ra bất kỳ lời giải thích nào.
Quuxplusone

1
Tôi đến trễ cho bữa tiệc, có vẻ như con trỏ thông minh cũng không làm việc
Nicholas Humphrey

28

Bạn cần có khả năng xử lý các đối số mẫu

template <std::string temp>
void f() {
 // ...
}

f<"foo">();
f<"bar">(); // different function!?

Bây giờ một cấy ghép sẽ cần phải đưa ra một chuỗi ký tự duy nhất cho std::string hoặc, cho vấn đề đó, bất kỳ lớp nào khác do người dùng xác định tùy ý, lưu trữ một giá trị cụ thể, ý nghĩa của nó không được triển khai. Ngoài ra, giá trị của các đối tượng lớp tùy ý không thể được tính toán tại thời điểm biên dịch.

Nó được lên kế hoạch để xem xét cho phép các loại lớp theo nghĩa đen làm các loại tham số mẫu cho post-C ++ 0x, được khởi tạo bằng các biểu thức hằng số. Chúng có thể bị xáo trộn bằng cách xử lý đệ quy các thành viên dữ liệu theo giá trị của chúng (ví dụ: đối với các lớp cơ sở, chúng ta có thể áp dụng theo chiều sâu đầu tiên, từ trái sang phải). Nhưng nó chắc chắn sẽ không hoạt động cho các lớp học tùy ý.


10

Đối số mẫu không phải kiểu được cung cấp trong danh sách đối số mẫu là một biểu thức có giá trị có thể được xác định tại thời điểm biên dịch. Các đối số như vậy phải là:

biểu thức hằng, địa chỉ của các hàm hoặc đối tượng có liên kết bên ngoài, hoặc địa chỉ của các thành viên lớp tĩnh.

Ngoài ra, chuỗi ký tự là các đối tượng có liên kết nội bộ, vì vậy bạn không thể sử dụng chúng làm đối số mẫu. Bạn cũng không thể sử dụng con trỏ toàn cục. Không cho phép các ký tự dấu phẩy động, do có khả năng làm tròn lỗi rõ ràng.


Bạn đã sử dụng một trích dẫn, vậy nguồn là gì? Tôi muốn ủng hộ nó nếu nó có nguồn để trích dẫn.
Gabriel Staples
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.