2015-08-24 17 views
11

Tôi nhìn một vài đề mục liên hệ stack overflow như This case of template function overloading eludes my understandingTại sao nó không hợp pháp đối với các chức năng không có khuôn mẫu để có cùng tên và đối số nhưng các kiểu trả về khác nhau? (Nhưng quy phạm pháp luật cho các chức năng mẫu?)

Function overloading by return type?

nhưng dường như không cho tôi một cách chính xác câu trả lời tôi đang tìm kiếm, ít nhất là không theo cách dễ hiểu cho tôi.

Câu hỏi của tôi nắm này: tại sao, từ cả một thiết kế và quan điểm kỹ thuật, là nó hợp pháp để làm điều này:

#include <iostream> 

using namespace std; 

template<class T> 
void func(){ 
    cout << "Compiler inferred from void return value!\n"; 
} 

template<class T> 
int func(){ 
    cout << "Compiler inferred from int return value!\n"; 
    return 0; 
} 

int main(){ 
    void (*thisFunc)()=func<int>; 
    int (*thatFunc)()=func<int>; 
    thisFunc(); 
    thatFunc(); 
} 

Nhưng không này:

#include <iostream> 

using namespace std; 

void func(){ 
    cout << "You won't see this because it won't compile!\n"; 
} 

int func(){ 
    cout << "Nor this one!\n"; 
    return 0; 
} 

int main(){ 
    void (*thisFunc)()=func; 
    int (*thatFunc)()=func; 
    thisFunc(); 
    thatFunc(); 
} 

Điều đáng nói ví dụ đầu tiên sẽ không biên dịch nếu tôi không đưa ra một tham số mẫu tùy ý một cách rõ ràng khi khởi tạo thisFunc và thatFunc. Sự khác biệt duy nhất giữa hai là cái đầu tiên có func templated bởi một loại đó là hoàn toàn không quan trọng, ngoại trừ việc nó dường như cho phép tôi quá tải theo kiểu trả về. Trình biên dịch thậm chí có thể đưa ra một suy luận trong trường hợp đó mà chức năng gọi, làm cho tính bất hợp pháp của quá tải hàm theo kiểu trả về trong C++ phần nào gây rắc rối cho tôi. Trong mọi trường hợp, đó là một mẹo nhỏ gọn tôi đoán.

EDIT: Điều làm phiền tôi nhất là sự mâu thuẫn: Tôi sẽ nghĩ rất lâu và khó trước khi tôi thực sự coi quá tải theo kiểu trả về, nhưng nếu "sửa" cho ai đó muốn bị quá tải theo kiểu trả về chỉ đơn giản là thêm một tham số mẫu vô nghĩa hoặc dường như bọc các hàm bên trong các không gian tên, sau đó tôi sẽ nghĩ C++ hoặc ít nhiều nghiêm ngặt về những gì nó coi là mơ hồ. Có lý do thuyết phục nào khiến các mẫu và không gian tên cần chức năng này để hoạt động chính xác không? Có một ví dụ về mã mong muốn mà không thể làm việc nếu, ví dụ, các mẫu không được phép phân định mã như trong ví dụ của tôi? Tôi hỏi từ quan điểm thiết kế ngôn ngữ, không phải là quan điểm tuân thủ trình biên dịch.

+0

Đối với mẫu, tôi nghĩ rằng đó là cho phép SFINAE hoặc loại trả về. – Jarod42

+3

Bạn không thực sự quá tải trên kiểu trả về, nhưng bằng cách sử dụng SFINAE, do đó hãy chọn mẫu instantiation duy nhất có thể cho mỗi con trỏ hàm. Khi bạn sử dụng 'func ', trong mỗi khai báo, chỉ có một mẫu trong đó thay thế hoạt động, nhưng nó không phải là lỗi cho một thay thế khác thất bại. Nó chỉ là bỏ qua. –

Trả lời

11

Nó không phải là không hợp lệ nói chung: có một cách để quá tải các chức năng không phải mẫu trên kiểu trả về. Nó chỉ là không hợp lệ theo cách bạn đang làm nó.

namespace A { 
    void func() {} 
} 
namespace B { 
    int func() { return 0; } 
} 
using A::func; 
using B::func; 
int main(){ 
    void (*thisFunc)()=func; 
    int (*thatFunc)()=func; 
    thisFunc(); 
    thatFunc(); 
} 

Biên dịch, liên kết này và chạy tốt.

Vì điều này hợp lệ và được chấp nhận bởi việc triển khai thực tế, nên rõ ràng rằng không có lý do kỹ thuật nào khiến mã của bạn không hợp lệ. Phải thừa nhận rằng nó sẽ yêu cầu một số thay đổi đối với tên mangling, vì thường không có chức năng mẫu không có kiểu trả về của họ trong tên bị xé, nhưng nó dễ dàng thực hiện được.

Điều còn lại là lý do hợp lý: quá tải các chức năng không phải mẫu trên kiểu trả về gần như chắc chắn là một sai lầm. Nó làm cho hàm không thể đọc được trong các ngữ cảnh bình thường, nó làm cho các chẩn đoán cực kỳ kém đối với các lỗi thường gặp (thay đổi một khai báo ở một nơi và quên đi nơi khác), nó có mức sử dụng rất hạn chế, vì vậy đừng làm điều đó.

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