2012-06-13 41 views
8

Yay, một tiêu đề câu hỏi khác bao gồm một chuỗi ngẫu nhiên các thuật ngữ C++!Chức năng chuyển đổi theo khuôn mẫu thành con trỏ chức năng

Thông thường chúng tôi tạo một lớp Có thể gọi bằng cách triển khai operator(). Nhưng bạn cũng có thể làm như vậy bằng cách thực hiện chuyển đổi do người dùng xác định để hoạt động con trỏ hoặc loại tham chiếu. Thay vì sử dụng chuyển tiếp hoàn hảo, một hàm chuyển đổi có thể trả về một con trỏ tới một hàm mà sau đó được gọi với danh sách đối số gốc.

struct call_printf { 
    typedef int printf_t(char const *, ...); 
    operator printf_t &() { return std::printf; } 
}; 

http://ideone.com/kqrJz

Theo như tôi có thể nói, các typedef trên là một điều cần thiết cú pháp. Tên của hàm chuyển đổi được tạo từ loại-specifier-seq, không cho phép cấu trúc như int (*)(). Điều đó sẽ yêu cầu một người khai báo trừu tượng . Có lẽ lý do là các tên kiểu như vậy trở nên phức tạp và các cấu trúc phức tạp được sử dụng làm tên đối tượng khó phân tích cú pháp.

Chức năng chuyển đổi cũng được phép được tạo mẫu, nhưng các đối số mẫu phải được suy luận, vì không có nơi nào để chỉ định rõ chúng. (Điều đó sẽ đánh bại toàn bộ các điểm chuyển đổi ngầm.)


Câu hỏi # 1: Trong C++ 03, là không có cách nào để xác định một hàm operator chuyển đổi mẫu? Nó xuất hiện không có cách nào để giải quyết các đối số mẫu (tức là, đặt tên chúng trong một bối cảnh suy luận) trong một kiểu con trỏ hàm có thể chấp nhận được.

Dưới đây là tham chiếu tương đương từ C++ 11, §13.3.1.1.2/2 [over.call.object]. Đó là cơ bản giống từ C++ 03:

Bên cạnh đó, đối với mỗi chức năng chuyển đổi không rõ ràng tuyên bố trong T có dạng

operator conversion-type-id() cv-qualifier attribute-specifier-seqopt; 

nơi cv-vòng loại là CV-cùng trình độ, hoặc bằng cv lớn hơn, cv, và nơi loại chuyển đổi-id biểu thị loại “con trỏ đến hàm (P1, ..., Pn) trở về R”, hoặc loại "Tham chiếu đến con trỏ đến hàm của (P1, ..., P n) trở R”, hoặc gõ‘tham chiếu đến chức năng (P1, ..., Pn) trở R’, một chức năng gọi thay thế với tên duy nhất gọi chức năng và có hình thức

R call-function (conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1,... ,an); } 

là cũng được coi là một chức năng ứng cử viên. Tương tự, các hàm gọi thay thế được thêm vào tập hợp các hàm ứng cử viên cho mỗi hàm chuyển đổi không rõ ràng được khai báo trong một lớp cơ sở của T cung cấp hàm không bị ẩn trong T bằng một tuyên bố can thiệp khác.


Câu hỏi # 2: Trong C++ 11, một sự chuyển đổi như vậy có thể được xác định bằng cách sử dụng mẫu đối số mặc định? Điều này rất hữu ích cho SFINAE. Sự khác biệt duy nhất ở đây từ ví dụ trên là loại chuyển đổi-id chỉ đại diện cho tham chiếu hàm sau khi khởi tạo, bởi vì đó là loại phụ thuộc (bất chấp sự bất biến).Điều này đi lên GCC và nó bỏ qua mẫu thành viên.

enum { call_alternate = true; } 

struct call_switch { 
    template< bool en = call_alternate > 
    operator typename std::enable_if< en, decltype(fn_1) & >::type() 
     { return fn_1; } 

    template< bool en = ! call_alternate > 
    operator typename std::enable_if< en, decltype(fn_2) & >::type() 
     { return fn_2; } 
}; 

Chúng tôi cũng có các mẫu bí danh. Có vẻ như thay thế bí danh xảy ra trước khi diễn giải, được đưa ra ví dụ trong §14.5.7/2, trong đó các tuyên bố của cuộc xung đột process. Trong GCC 4.7, mã này ít nhất là instantiates khai báo, nhưng sau đó nó tạo ra một kỳ lạ "ứng cử viên mong đợi 2 đối số, 2 cung cấp" lỗi.

template< typename t > 
using fn_t = void (&)(t); 

struct talk { 
    template< typename t > 
    operator fn_t<t>() { return fn; } 
}; 

int main() { 
    talk()(3); 
} 
+7

Lòng tốt của tôi .... –

+0

Bạn đang cố gắng làm gì? Nó có thể hữu ích ở đâu? – Nawaz

+0

@Nawaz khi bạn muốn toán tử chuyển đổi hoạt động các loại con trỏ? –

Trả lời

3

Câu hỏi # 1: Trong C++ 03, là không có cách nào để xác định một hàm operator chuyển đổi mẫu? Nó xuất hiện không có cách nào để giải quyết các đối số mẫu (tức là, đặt tên chúng trong một bối cảnh suy luận) trong một kiểu con trỏ hàm có thể chấp nhận được.

Vâng, đó là chính xác.

Câu hỏi # 2: Trong C++ 11, chuyển đổi như vậy có thể được chỉ định bằng cách sử dụng đối số mẫu mặc định không?

Có thể và bạn cũng có thể sử dụng mẫu bí danh, nhưng bạn không thể sử dụng mẫu chức năng chuyển đổi như vậy để tạo hàm gọi thay thế. Bạn có thể sử dụng nó để chuyển đổi đối tượng lớp của bạn thành con trỏ hàm trong chuyển đổi ngầm định nếu không.

Chúng tôi cũng có các mẫu bí danh. Dường như việc thay thế bí danh xảy ra trước khi khởi tạo, đưa ra ví dụ trong §14.5.7/2, nơi mà các khai báo về xung đột quy trình. Trong GCC 4.7, mã này ít nhất là instantiates khai báo, nhưng sau đó nó tạo ra một kỳ lạ "ứng cử viên mong đợi 2 đối số, 2 cung cấp" lỗi.

Có, đây là https://groups.google.com/forum/?fromgroups#!topic/comp.std.c++/lXLFBcF_m3c (và gây ra việc đóng cửa của DR395), nhưng cho dù như vậy một chức năng chuyển đổi mẫu có thể làm việc trong các trường hợp như void(&p)() = yourClassObject, nó sẽ không làm việc cho các chức năng cuộc gọi thay thế, vì có nhu cầu chuyển đổi chức năng để cung cấp một loại không phụ thuộc cố định mà đối tượng lớp được chuyển đổi khi hàm thay thế được gọi, nhưng mẫu chức năng chuyển đổi không cung cấp kiểu như vậy bình thường (những thứ lạ như template<typename = int> operator Identity<void(*)()>(); sang một bên ...).

Tôi nghĩ rằng GCC có thể tạo ra ứng cử viên call-function(void (&)(t), t) không chính xác với các kiểu phụ thuộc và cố gắng gọi ứng viên đó, do đó vi phạm một số bất biến của nó (có thể giải thích thông báo lỗi lạ - có thể đánh bất ngờ ở đâu đó).

+0

Câu trả lời hay, ngoại trừ "phải rõ ràng" tại sao? Hàm chuyển đổi từ ngữ được khai báo trong T của biểu mẫu 'toán tử' * conversion-type-id *'() '" không nói gì về việc không phải là mẫu. – Potatoswatter

+0

@Potatoswatter tôi nghĩ rằng đó là một thiếu sót trong spec. Nhưng nó chỉ không có ý nghĩa với tôi để xem xét các mẫu chức năng chuyển đổi ở đây. Điều gì nên là ngữ nghĩa? –

+0

Miễn là loại chức năng có thể được suy ra từ danh sách đối số sử dụng độ phân giải quá tải, thì không cần ngữ nghĩa đặc biệt.Đó chỉ là những gì GCC đang làm (nửa chừng). Về cơ bản hàm gọi thay thế trở thành một mẫu hàm gọi thay thế. – Potatoswatter

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