2010-09-27 36 views
11

Phần 4.3 của C++ Templates bang 'Không có khả năng sử dụng literals dấu phẩy động (và biểu thức hằng số dấu chấm động đơn giản) như các đối số mẫu có lịch sử lý do.'Template chuyên môn hóa với phao là không loại

Tương tự,

$ 14,1/7 quốc gia - "Một phi loại mẫu tham số không được tuyên bố có dấu chấm động, lớp, hoặc kiểu void [Ví dụ:

.
template<double d> class X; // error 
template<double* pd> class Y; // OK 
template<double& rd> class Z; // OK" 
  1. lý do lịch sử đó là Bein là gì g nói về cuốn sách trong câu nói trên?

  2. Nhìn vào lý do tại sao Y và Z là hợp lệ nhưng không phải X, là toàn bộ thử thách liên quan đến việc có các tham số mẫu không kiểu nổi có phải làm gì với con trỏ/tham chiếu không?

  3. Tại sao mẫu thông số không loại có thể không thuộc loại lớp?

+0

@aaa cá chép: Có, tôi có thể đoán ra điều đó. Tôi tò mò lý do lịch sử cho việc không cho phép các loại dấu phẩy động. Ngoài ra, tôi đang cố gắng hiểu tại sao X bị hình thành không phải bởi Y hoặc Z. – Chubsdad

+0

http://groups.google.com/group/comp.lang.c++/browse_thread/thread/2f4c0b5a5ae627bc/bbe916d9e75426de?hl=vi&ie=UTF -8 & oe = utf-8 & q = dấu chấm động + dấu +% 28as + mẫu + đối số + lý do + lịch sử & pli = 1 – Anycorn

+0

@aaa cá chép: không, không phải. Địa chỉ được thông qua sẽ chỉ được biết đến với trình liên kết, nhưng trình biên dịch đã cần nó để khởi tạo. – MSalters

Trả lời

5

Số dấu phẩy động không có đại diện chung (và một số giá trị không thể đại diện mà không có tổn thất chính xác vì nó có thể khác nhau từ nền tảng này sang nền tảng khác). trên các nền tảng khác nhau.

(Người ta có thể nói như C++ hỗ trợ biên dịch chéo mà không đòi hỏi trình biên dịch bắt chước đầy đủ số học dấu chấm động của máy mục tiêu. Cho phép float hay double như một tham số mẫu sẽ làm mất hiệu lực này.)

template<float F> 
float squared_float() 
{ 
return F * F; 
} 

Ví dụ: squared_float < 1.0> có thể có cùng chức năng như squared_float < 1.00000001> trên một số triển khai, trong khi trên những người khác, chúng sẽ là hai hàm khác nhau.


A reference to a float có nghĩa là trình biên dịch có thể tối ưu hóa nó vì nó biết giá trị của nó và không bao giờ thay đổi.

Đối với pointer, cũng chỉ là một kiểu dữ liệu phụ thuộc vào kiến ​​trúc khác (32bit/64bit) không liên quan gì đến phao.

+0

Tuy nhiên, trên một nền tảng nhất định không phải là vấn đề. Tuy nhiên, điều này có thể ảnh hưởng đến tính di động, điều này đúng với rất nhiều tính năng khác trong ngôn ngữ, ví dụ: sizeof (int) – Chubsdad

10

Có thể khó chọn đúng mẫu ngay lập tức, vì có thể xảy ra lỗi làm tròn.

xem xét như sau:

template<float n> 
void f(n) {...} //Version 1 

template<0.3333> 
void f() { ...} // Version 2:Specialization for 0.3333 

f(1/3); -> Phiên bản nào sẽ được gọi là?

Xét đoạn mã sau:

template <float f> class foo { ... }; 
foo<1E6 + 1E-6> my_foo; 

"nên trình biên dịch tạo ra gì Trình biên dịch có biết về các chi tiết của mục tiêu kiến ​​trúc dấu chấm động để có thể chạy nhanh chóng các mẫu Đây là. đủ dễ dàng nếu trình biên dịch đang chạy trên kiến ​​trúc đích , nó chỉ có thể tính toán và tìm ra câu trả lời, nhưng nếu bạn đang biên dịch chéo, trình biên dịch sẽ phải tổng hợp được hành vi điểm nổi của mọi kiến trúc mục tiêu dự kiến. Và may mắn là Ủy ban Tiêu chuẩn đã quyết định rằng điều này sẽ không hợp lý. "

trơ trẽn sao chép từ here.

Tại sao các thông số mẫu không loại không thể loại lớp

Theo hiểu biết của tôi một tổ chức phi-type paramater không thể loại lớp bởi vì có thể có nhiều hơn một triển khai của một lớp học. Ví dụ:

template <typename T> 
class demo{...}; 

template <>  
class demo<int>{...}; 


template <typename T, demo d> //which demo?? demo<T> or demo<int> 
class Example{...}; 

Không thể sử dụng các lớp địa phương làm thông số mẫu vì they don't have external linkage.

+0

0.3333 là loại 'đôi' không phải là nó giống như loại 1/3? Vì vậy, trình biên dịch có thể chọn chuyên môn cho 'double' với mặc định là <0.3333> – Chubsdad

+0

có vẻ hợp lý, IEEE repr đã được giới thiệu vào năm 1985, cùng thời điểm C++ trở thành "chính thức", vì vậy có lẽ không có toán học chuẩn cho dấu phẩy động – Anycorn

+1

@Chubsdad : Xem [this] (http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/a7e278eeb134072c/e8f65e0d90cadf7e?lnk=gst&q=floating+point+literals+as+template+arguments# e8f65e0d90cadf7e) comp.lang.C++ thread –

1

Việc mã hóa chính xác các giá trị dấu phẩy động là tùy thuộc vào các quirks của từng CPU. Ví dụ, trong việc đánh giá một biểu thức được cho là hằng số, liệu một CPU có sử dụng các thanh ghi CPU 80 bit có độ chính xác cao hơn và chỉ quay lại 64-bit ở cuối? Nếu một trình biên dịch nói có và khác không - mẫu sẽ nhận được hai instantiations riêng biệt. Tuy nhiên, một số trình biên dịch khác chỉ có thể có các thanh ghi 64 bit và có lẽ các CPU khác nhau có thể thay đổi theo giá trị epsilon. Thứ tự mà trong đó một số trình biên dịch chọn để đánh giá một biểu thức, hoặc liệu một thư viện đã được biên dịch bằng cách sử dụng một thư viện mô phỏng dấu phẩy động vv có thể gây ra các kết quả phù hợp không. Hơn nữa, các số dấu phẩy động có một số trường hợp cạnh lạ: dương và âm 0 vv, mà hành vi sẽ phải được xác định.

Những vấn đề này có khả năng xảy ra trong môi trường nơi các đối tượng được biên dịch trên các máy khác nhau (với các CPU khác nhau, phiên bản trình biên dịch và cờ vv), nhưng cần liên kết đáng tin cậy. Các doanh nghiệp thường làm điều này, và các thư viện phân tán nhị phân phải đối mặt với những vấn đề như vậy. Trình biên dịch C++ thường cố gắng áp dụng một số Giao diện nhị phân ứng dụng (ABI) nhất quán nhất có thể trên các phiên bản và môi trường, nhưng hiện tại chúng không chuẩn hóa cách các thông số điểm trôi nổi được tính toán. mong đợi tất cả các trình biên dịch sử dụng cùng một mô phỏng điểm nổi phần mềm để lấy được các giá trị. Điều đó sẽ có nỗ lực phối hợp, và các giải pháp thi đua hiện tại có thể có vấn đề cấp phép.

Điều thú vị là Walter Bright (của Digital Mars) nghĩ rằng tất cả đều là crap và cho phép các hằng số dấu chấm động trong D ... đoán rằng anh ta đang nhận được một số kinh nghiệm thực tế về hậu quả có ích cho cộng đồng C++, nhưng tôi đã không nghe nói gần đây.

+0

có một số công cụ MPL trong kho tăng cường cho phép các hằng số FP. – Anycorn

+0

hmmm ... Tôi tránh MPL - sự bực tức không chịu từ chối nhà Loki trong khi các tài liệu trực tuyến sẵn có cho MPL là tồi tệ nhất trong toàn bộ bộ sưu tập tăng và IMHO trắng trợn "Tôi sẽ kiếm tiền ở đây vì tôi kiểm soát thúc đẩy "quảng cáo cho sách, trong khi các tác giả tăng cường khác được mong đợi sẽ thực sự sống bằng cách" chia sẻ nó một cách tự do với cộng đồng "tinh thần tăng cường thích thú công khai –

+0

[Chúng tôi có thể yêu cầu anh ta] (http://stackoverflow.com/users/ 33949/walter-bright) –

1

Giải pháp cho vấn đề này là sử dụng các số hữu tỷ. Gửi hai tham số không phải kiểu số nguyên và sau đó khởi tạo phao của bạn trong hàm tạo như sau

template<int dNum =1, int dDen = 3> 
class myclass { 
    double d; 
    myclass: d(dNum/dDen) {} 
}; 

voila, đi qua float.

+0

Nếu sử dụng C++ 11, 'std :: ratio' hoạt động tốt cho việc này. – Ponkadoodle

+0

Nhưng làm thế nào để bạn biến tỷ lệ :: std thành float? – Ant6n

0

Một giải pháp khả thi cho vấn đề này là sử dụng loại có giá trị không đổi là phao, sau đó sử dụng loại đó làm thông số mẫu. Ví dụ, nếu bạn muốn có một đa thức số nguyên, nói, và muốn đánh giá nó tại một số giá trị điểm thời gian biên dịch nổi:

template <int a, int b, int c> 
class Polynomial { 
public: 
    template <typename t> 
    static constexpr float eval() { 
     return a*t::value*t::value + b*t::value + c; 
    } 
}; 

class THREE_POINT_FIVE { 
public: 
    static constexpr float value = 3.5f; 
}; 

int main() { 
    constexpr float y = Polynomial<2, 0, 1>::typename eval<THREE_POINT_FIVE>(); 
    std::cout << y << std::endl; 
} 

Người ta cũng có thể sử dụng các lớp helper mà cho phép tạo ra các lớp học của phao nổi, ví dụ cho phần trăm:

template <unsigned int p> 
class PERCENT { 
public: 
    static constexpr float value = p * 0.01f; 
}; 

... 
constexpr float y2 = Polynomial<2, 0, 1>::typename eval<PERCENT<43>> 
... 

Tôi đoán điều này tương tự như sử dụng std::ratio được đề cập trước đây.

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