2013-04-07 26 views
8

Khi trả lời this question, tôi đã thử đoạn code sau đây với gcc (code compiled) và kêu vang (code rejected):constexpr tĩnh trỏ-to-chức năng, sự khác biệt giữa các trình biên dịch

typedef long (*func)(int); 

long function(int) { return 42; } 

struct Test 
{ 
    static constexpr func f = &function; 
}; 

template<func c> 
struct Call 
{ 
    static void f() 
    { 
     c(0); 
    } 
}; 

int main() 
{ 
    Call<Test::f>::f(); 
} 

Tôi không chắc chắn mà trình biên dịch là đúng, mặc dù tôi nghĩ rằng việc khởi tạo constexpr của Test::f là ok. Các đầu ra lỗi kêu vang là:

error: non-type template argument for template parameter of pointer type 'func' 
     (aka 'long (*)(int)') must have its address taken 
  1. nào biên dịch là đúng?
  2. Nếu tiếng kêu là đúng, tại sao và lỗi này thực sự có ý nghĩa gì?

EDIT: vì "lý do", xem DyP's question.

+0

Tôi đang tự hỏi có hay không '& function' thực sự là một khởi tạo giá trị cho' constexpr'. Cả hai trình biên dịch dường như nghĩ như vậy. Nhưng có vẻ như tôi không thích. Điều đó không được biết tại thời gian biên dịch, chỉ vào thời gian liên kết. – Omnifarious

+0

'& function' là địa chỉ của một hàm, vì vậy đối với tôi nó được biết ở thời gian biên dịch ... Ví dụ, bạn có thể chuyển một con trỏ tới hàm như một đối số mẫu. – Synxis

+1

Một con trỏ tới một hàm là một thứ ... nếu đây là một phần của một thư viện được chia sẻ, ví dụ, làm thế nào mà địa chỉ có thể đủ điều kiện như là một 'constexpr'? –

Trả lời

8
luận

14.3.2 Mẫu phi loại [temp.arg.nontype]

Mẫu đối số cho một tổ chức phi loại, phi mẫu template-tham số sẽ là một trong:

[...]

- một biểu thức hằng số (5,19) mà chỉ định địa chỉ của một đối tượng với tĩnh lưu trữ> thời gian và bên ngoài hoặc nội bộ liên kết hay một chức năng với bên ngoài hoặc nội bộ liên kết, bao gồm mẫu chức năng và chức năng template -trí nhưng ngoại trừ uding thành viên lớp không tĩnh, thể hiện (bỏ qua dấu ngoặc đơn) như & id-expression, ngoại trừ & có thể bỏ qua nếu tên đề cập đến hàm hoặc mảng và sẽ bị bỏ qua nếu tham số mẫu tương ứng là tham chiếu; [...]

(n3485, tôi nhấn mạnh)

Tôi không biết chính xác lý do tại sao nó được hạn chế, nhưng tôi nghĩ rằng nó có thể liên quan đến một thực tế rằng địa chỉ chức năng không có sẵn tại thời gian biên dịch (có thể thay thế cho các mục đích tạo bản mẫu).


Edit: Tăng cường câu trả lời do một câu hỏi tiếp theo (comment) của Synxis

constexpr func = &function; 

^đây là tốt được hình thành; bạn có thể sử dụng địa chỉ của hàm để khởi tạo đối tượng constexpr. Vấn đề là nó bị cấm một cách rõ ràng để sử dụng con trỏ như không kiểu mẫu lập luận khác hơn của mẫu &identifier:

using My_Call  = Call < &function >; // fine 

constexpr func mypointer = &function; // fine 
using My_Ind_Call = Call <func>;  // forbidden, argument not of form `&id` 
+3

Điều này có vẻ như một sự giám sát. Nếu bạn gán một điều 'constexpr' cho một' constexpr' và sau đó gán nó cho một 'constexpr' khác, nó sẽ được chuyển đổi. – Omnifarious

+3

@Omnifarious It ** là ** 'constexpr'. Nhưng nó bị cấm một cách rõ ràng như một đối số không kiểu mẫu. – dyp

+0

Vâng, điều đó thật thú vị. Rõ ràng không được xử lý trực giao. Tôi tự hỏi lý do là gì. Mặc dù, tôi có một sự nghi ngờ mạnh mẽ. Tôi đoán là các đối tượng có thể được di chuyển bởi trình liên kết được gọi theo tên trong các quy tắc mangling cho các mẫu. Yêu cầu trình biên dịch để mang theo tên gốc cho 'constexpr' những thứ như vậy là khá nặng nề và có thể không thể trong một số kịch bản. – Omnifarious

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