2010-07-22 31 views
13

Tôi có cấu trúc để lưu trữ chức năng gọi lại như thế này:Sử dụng mẫu để trả về giá trị. làm thế nào để xử lý trở lại void?

template<class T> 
struct CommandGlobal : CommandBase 
{ 
    typedef boost::function<T()> Command; 
    Command comm; 

    virtual T Execute() const 
    { 
     if(comm) 
      return comm(); 
     return NULL; 
    } 
}; 

Có vẻ như nó sẽ làm việc tốt trừ khi T là khoảng trống vì Execute chức năng muốn trả về giá trị ..

giải pháp tốt nhất là gì cho vấn đề này?

Cảm ơn!

+2

Giả sử đó là 'if (comm)'? – GManNickG

+0

Thật vậy. Sửa lỗi ngay bây giờ. –

Trả lời

11

Câu trả lời này được dựa trên this fun-fact: Trong hàm trả về void, bạn có thể trả về bất kỳ biểu thức nào trong đó loại bị vô hiệu.

Vì vậy, giải pháp đơn giản là:

virtual T Execute() const 
{ 
    if (comm) // boolean logic change, typo in OP? 
     return comm(); 
    else 
     return static_cast<T>(NULL); 
} 

Khi T = void, báo cáo kết quả lợi nhuận cuối cùng là tương đương với return;.


Tuy nhiên, tôi cảm thấy đây là thiết kế kém. Là NULL có ý nghĩa cho mỗiT? Tôi không nghĩ vậy. Tôi sẽ ném một ngoại lệ:

virtual T Execute() const 
{ 
    if (comm) 
     return comm(); 
    else 
     throw std::runtime_error("No function!") 
} 

Tuy nhiên, điều này được thực hiện automatically by Boost, do đó, mã của bạn sẽ trở thành nhiều bụi:

virtual T Execute() const 
{ 
    return comm(); 
} 

Sau đó, bạn có thể thêm chức năng bổ sung, chẳng hạn như:

bool empty(void) const 
{ 
    return !comm; // or return comm.empty() if you're the explicit type 
} 

Vì vậy, người dùng có thể kiểm tra xem nó có thể được gọi trước khi gọi nó. Tất nhiên tại thời điểm này, trừ khi lớp học của bạn có chức năng bổ sung mà bạn đã bỏ ra vì lợi ích của câu hỏi, tôi thấy không có lý do gì để không chỉ sử dụng boost::function ngay từ đầu.

+2

là dàn diễn viên kiểu C tôi đang thấy ở đó? – akira

+0

@akira: Đã qua rồi. :) Chỉ cần tạm thời trước khi tôi chạm vào nó một chút. – GManNickG

4

Nếu nó chỉ là báo cáo kết quả return, điều này sẽ làm các trick:

virtual T Execute() const 
{ 
    if(comm) 
     return comm(); 
    return T(); 
} 

Nếu có nhiều đến nó, chuyên các mẫu cho void.

+1

Giả định rằng 'T' là cấu hình mặc định. –

+1

@Georg: Đúng vậy. Tuy nhiên, một số giả định bạn phải tạo và tạo một đối tượng mặc định khi bạn không có đối tượng nào ít có hại hơn giả định của mã ban đầu là 'T' có thể được xây dựng từ' NULL' (không thành công nếu 'T' là một 'std :: string'). Nếu vẫn thất bại, bạn vẫn có thể tạo một chuyên môn để tạo đối tượng theo một cách khác hoặc đặt mã tạo giá trị trả về mặc định vào một chính sách. – sbi

+1

Không có nghĩa là để ngụ ý nó không phải là một lựa chọn, tôi chỉ nghĩ rằng nó không rõ ràng cho tất cả mọi người và tốt hơn sẽ được chỉ ra :) –

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