2013-07-18 31 views
11

Năm 2003 - vâng, - Vandervoorde và Josuttis viết này trong cuốn sách của họ "C++ Mẫu" (p 40).:Tại sao đôi không được phép làm thông số mẫu không phải kiểu?

Không có khả năng sử dụng literals dấu phẩy động (và floating- liên tục đơn giản biểu thức điểm) dưới dạng đối số mẫu có lý do lịch sử. Vì không có những thách thức kỹ thuật nghiêm trọng, điều này có thể được hỗ trợ trong các phiên bản tương lai của C++.

Nhưng điều này vẫn không hoạt động, ngay cả trong môi trường C++ 11:

template<double D> //error 
void foo() {} 

Tại sao đây không phải thêm vào?

+11

Cho rằng bình đẳng dấu chấm động là một trơn khái niệm, tôi không chắc làm thế nào họ có thể nói "không có những thách thức kỹ thuật nghiêm trọng." Tôi thà nghĩ rằng điều này sẽ đầy nguy hiểm –

+0

@ ErnestFriedman-Hill: Điều đó có vẻ giống như cơ sở của một câu trả lời cho tôi. –

+0

Chúng tôi đối phó với các vấn đề bình đẳng trong mã thời gian chạy thường xuyên, mặc dù. Những lời khuyên tương tự sẽ áp dụng cho việc sử dụng chúng trong các mẫu ... Tôi thực sự không thấy lý do chính đáng nào để giữ chúng trong thời gian chạy. –

Trả lời

10

Tôi đã luôn luôn giả định rằng nó phải liên quan đến việc triển khai kết hợp với nhau. Giống như hai trường hợp này giống nhau hoặc khác nhau:

template class foo<10./3.> 
template class foo<1./3 * 10.> 

Chúng không thể tạo ra cùng một biểu diễn chính xác kép, do đó trình biên dịch có thể coi chúng là các lớp khác nhau. Sau đó, bạn không thể gán chúng cho nhau, v.v.

5

Khi sử dụng số dấu phẩy động, có rất nhiều vấn đề với làm tròn và bình đẳng. Từ quan điểm của ủy ban bình thường hóa, bạn cần đảm bảo rằng hai chương trình thực hiện giống nhau trên một số trình biên dịch. Vì vậy, bạn cần phải xác định chính xác kết quả của hoạt động điểm nổi là gì. Có lẽ họ cảm thấy rằng chuẩn IEEE-754 không đủ chính xác ...

Vì vậy, đây không phải là câu hỏi có thể thực hiện được hay không nhưng hành vi chính xác chúng ta muốn có.

Lưu ý rằng constexpr chấp nhận giá trị dấu phẩy động. Điều này thường đủ để tính toán thời gian biên dịch.

7

Hãy nhìn vào đoạn mã sau:

template<double D> int f(){ 
    static int i=0; 
    ++i; 
    return i; 
} 

... 

#define D1=... 
#define D2=... 
cout << f<D1>()<<endl; // returns 1 
cout << f<D1-D2+D2>()<<endl; // may return 1 or 2, depending on many things 

Xem, D1-D2+D2 có thể tương đương với D1 cho một số giá trị nhưng không bình đẳng cho những người khác.

Quan trọng hơn - họ có thể bằng hoặc không tùy thuộc vào các thiết lập làm tròn

Và cuối cùng, họ có thể bằng hoặc không tùy thuộc vào trình biên dịch/kiến ​​trúc/nhiều thứ khác.

Vấn đề là, hoạt động điểm nổi không cũng đủ định nghĩa cho mẫu sử dụng (chúng được định nghĩa tốt, nhưng có rất nhiều khả năng sai tùy thuộc vào tùy chọn khác nhau)

+0

"phụ thuộc vào cài đặt" là không có lý do. 'sizeof (Foo)' cũng có thể phụ thuộc vào các thiết lập, nhưng được cho phép rõ ràng. – MSalters

+1

Có, nhưng cài đặt cho 'sizeof' đánh giá tại thời gian biên dịch, và các mẫu cũng được đánh giá tại thời gian biên dịch. Mặt khác, các cài đặt làm tròn có thể thay đổi khi chạy. Điều này dẫn đến một trường hợp hai float chính xác như nhau (các thiết lập làm tròn thời gian chạy), nhưng các mẫu tương ứng của chúng khác nhau (khi tính toán tạo ra chúng dẫn đến các giá trị khác nhau tại thời gian biên dịch). Trong ví dụ của tôi, nếu bạn tính toán 'D1-D2 + D2' khi chạy, bạn có thể nhận được chính xác' D1', nhưng các mẫu vẫn được đánh giá theo các hàm khác nhau. – rabensky

+0

Ví dụ của bạn có vẻ lạ. "Có thể trả lại 1 hoặc 2". Tuy nhiên, D thậm chí không được sử dụng trong chức năng. Tôi đang thiếu gì? –

Các vấn đề liên quan