2013-09-27 71 views
11

Trong khi thực hiện một logger đơn giảnTại sao một con trỏ hàm không bị bắt bởi tham chiếu chung?

struct DebugOutput { 
    DebugOutput(std::ostream& out = std::cerr) : m_Out(out) {} 

    template<typename T> 
    inline DebugOutput& operator <<(T&& value) { 
     m_Out << value; 
     return *this; 
    } 
private: 
    std::ostream& m_Out; 
}; 

tôi phát hiện ra std::endl sẽ không bị bắt bởi các universal reference.

DebugOutput dbg; 
dgb << std::endl; 

tôi thấy this post này mà giải thích bạn cần phải thêm một chức năng quá tải trong cấu trúc mà mất đặc biệt là con trỏ chữ ký chức năng, ví dụ:

typedef std::ostream& (*StandardEndLine)(std::ostream&); 
inline DebugOutput& operator<<(StandardEndLine manip) { 
    return *this; 
} 

Tại sao con trỏ hàm được không bị bắt bởi các phổ quát tài liệu tham khảo ? Đây không phải là loại int hoặc void*?

+0

Đó là một mẫu/quá tải. – Xeo

+3

http://stackoverflow.com/a/1136617/46642 –

+0

có thể trùng lặp của [std :: endl là loại không xác định khi toán tử quá tải <<] (http://stackoverflow.com/questions/1134388/stdendl-is- của không biết-loại-khi-quá tải-nhà điều hành) – Xeo

Trả lời

12

Hàm (con trỏ) có thể bị ràng buộc với tham chiếu chung. Ví dụ:

void f(int) {} 

template <typename T> 
void foo(T&&) {} 

foo(f); // OK 

Tuy nhiên, chức năng quá tải không thể. Nghĩa là, nếu bạn thêm một tình trạng quá tải thứ hai của f, nói,

void f(double) {} 

các cuộc gọi foo(f) sẽ thất bại.

Đặt mình vào giày trình biên dịch. Cần phải vượt qua f đến foo và có hai hàm có tên là f mỗi hàm có một loại khác nhau. Nếu chúng tôi thông báo cho loại, thì trình biên dịch có thể chọn chính xác f. Ví dụ,

foo(static_cast<void (*)(int)>(f)); 

biên dịch tốt và sẽ vượt qua void f(int) (sau khi chức năng-to-con trỏ chuyển đổi) để foo.

Tuy nhiên, chúng tôi không thông báo cho loại. Chúng tôi yêu cầu trình biên dịch suy luận nó.

Tương tự như f, lập luận tương tự áp dụng cho std::endl bởi vì đây là một hàm mẫu và, do đó, tên std::endl đại diện cho một tập hợp các chức năng, tất cả có cùng tên nhưng khác nhau.

Bây giờ, bạn có thể thấy rằng nguyên nhân của lỗi là việc chúng tôi cung cấp tập quá tải và yêu cầu khấu trừ loại. Do đó, điều này không dành riêng cho các tham chiếu phổ quát.

std::cout << std::endl hoạt động vì basic_ostream::operator << không phải là mẫu và không cố gắng suy ra loại đối số được truyền. Đó là một hàm có một loại cụ thể là std::endl.

+0

Khá rõ ràng! Cảm ơn bạn @ cassio-neri :) –

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