2014-11-01 18 views
14

Chương trình sau đây biên dịch với cả gcc và clang, nhưng đây thực sự là chuẩn C++ 11 hoặc làm cả hai trình biên dịch chọn để hỗ trợ nó cho thuận tiện?Truyền con trỏ đối tượng làm đối số đầu tiên cho hàm thành viên: có phải là tiêu chuẩn không?

struct Foo { 
    int i; 

    void bar() { std::cout << i << std::endl; } 
}; 

int main() { 
    std::function<void(Foo*)> method = &Foo::bar; 

    Foo myFoo{4}; 
    method(&myFoo); // prints 4 
} 

Điều này chắc chắn thuận tiện, nhưng tôi không hiểu tại sao nó hoạt động.

+0

Nó hoạt động như với bất kỳ con trỏ hàm thành viên lớp nào, yêu cầu _'this'_ để gọi (chỉ ẩn nội dung xấu). Bạn không hiểu gì đặc biệt? Câu hỏi của bạn hơi quá rộng. –

+0

Vâng, đó là tiêu chuẩn. G + + hỗ trợ điều này ở đây, mặc dù: https://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html – Deduplicator

+2

@ πάνταῥεῖ: Tôi nghĩ anh ấy tò mò rằng đây dường như là nơi mà tiêu chuẩn cho thấy việc triển khai chi tiết rằng 'this' là một đối số cho các hàm thành viên. –

Trả lời

9

Vâng, đó là tiêu chuẩn. [Func.wrap.func.inv] xác định rằng operator()(ArgTypes&&... args)
của std::function cuộc gọi

gọi(f, std::forward<ArgTypes>(args)..., R) (20.8.2), nơi f là đối tượng mục tiêu (20.8.1) của *this.

(Trong trường hợp R là loại định trở lại.)

[func.require] định nghĩa INVOKE:

Xác định INVOKE(f, t1, t2, ..., tN) như sau:

  • (t1.*f)(t2, ..., tN) khi f là một con trỏ tới một hàm thành viên của một lớp Tt1 là một đối tượng kiểu T hoặc một tham chiếu đến một đối tượng loại T hoặc một tham chiếu đến một đối tượng của một loại có nguồn gốc từ T;

  • ((*t1).*f)(t2, ..., tN) khi f là một con trỏ tới một hàm thành viên của một lớp Tt1 không phải là một trong những loại được mô tả trong mục trước;

  • [...]

Lưu ý rằng các dấu R trong cuộc gọi được sử dụng cho việc chuyển đổi để R (kiểu trả về của function):

Xác định INVOKE(f, t1, t2, ..., tN, R) dưới dạng INVOKE(f, t1, t2, ..., tN) chuyển đổi hoàn toàn thành R.

Đối số đầu tiên và duy nhất bạn đưa ra là con trỏ tới Foo -object. Cuộc gọi đến method do đó dẫn đến cuộc gọi (void)((*t1).*f)(), khi được viết với các giá trị đã cho của bạn, tương đương với
((*(&myFoo)).&Foo::bar)(), tương đương với myFoo.bar().

+4

Một sự xấu hổ họ không chỉ xác định một chức năng 'std :: invoke' trong khi họ đang ở đó ... – Deduplicator

+0

@Deduplicator Vâng, nó ít nhiều được thực hiện một cách trivially - người ta phải xem xét xếp hạng thông qua độ phân giải quá tải dựa trên ưu tiên cơ chế mặc dù, đã có một thực hiện bị lỗi trong libstdC++ IIRC. – Columbo

+0

Những gì những gì! Bạn cũng có thể tạo một điểm chức năng cho dữ liệu thành viên? ('std :: function data = & Foo :: i;') Tôi đang học tất cả mọi thứ ngày hôm nay. – Barry

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