2010-08-08 30 views
11

Hãy xem xét đoạn mã sau:trở về từ một hàm Void trong C++

void Foo() 
{ 
    // ... 
} 

void Bar() 
{ 
    return Foo(); 
} 

là gì một lý do chính đáng để sử dụng trên trong C++ như trái ngược với cách tiếp cận phổ biến hơn:

void Foo() 
{ 
    // ... 
} 

void Bar() 
{ 
    Foo(); 

    // no more expressions -- i.e., implicit return here 
} 

Trả lời

16

Có thể không sử dụng trong ví dụ của bạn, nhưng có một số trường hợp khó xử lý void trong mã mẫu và tôi hy vọng quy tắc này sẽ giúp với điều đó đôi khi. ví dụ rất giả tạo:

#include <iostream> 

template <typename T> 
T retval() { 
    return T(); 
} 

template <> 
void retval() { 
    return; 
} 

template <> 
int retval() { 
    return 23; 
} 

template <typename T> 
T do_something() { 
    std::cout << "doing something\n"; 
} 

template <typename T> 
T do_something_and_return() { 
    do_something<T>(); 
    return retval<T>(); 
} 

int main() { 
    std::cout << do_something_and_return<int>() << "\n"; 
    std::cout << do_something_and_return<void*>() << "\n"; 
    do_something_and_return<void>(); 
} 

Lưu ý rằng chỉ main có để đối phó với thực tế là trong trường hợp void không có gì để trở về từ retval là. Hàm trung gian do_something_and_return là chung.

Tất nhiên, điều này chỉ giúp bạn cho đến thời điểm này, nếu bạn muốn lưu trữ retval trong biến và làm điều gì đó với nó trước khi trở về, thì bạn vẫn gặp rắc rối - bạn phải chuyên (hoặc quá tải) do_something_and_return cho khoảng trống.

+0

Cảm ơn. Tất cả các câu trả lời đều tốt, nhưng điều này minh họa cho điểm độc đáo. – kirk0

0

duy nhất lý do tôi có thể nghĩ là nếu bạn có một danh sách dài các câu lệnh return Foo(); trong một công tắc và muốn làm cho nó gọn hơn.

9

Đây là một công trình khá vô ích, không phục vụ mục đích, trừ khi được sử dụng với các mẫu. Tức là, nếu bạn đã xác định các hàm mẫu trả về một giá trị có thể là 'void'.

+4

sau đó nó hầu như không "vô ích", phải không? ;) – jalf

+0

@ jalf: Vâng, ở dạng nó được thể hiện trong câu hỏi nó khá là vô ích, phải không? ;-) –

+0

đủ chính xác. Tôi giải thích mã trong câu hỏi như là một ví dụ về tính năng ngôn ngữ và hỏi khi nào tính năng ngôn ngữ * nói chung * rất hữu ích. Nhưng điểm công bằng. ;) – jalf

7

Bạn sẽ sử dụng mã này trong mã chung, trong đó giá trị trả về của Foo() không xác định hoặc có thể thay đổi. Hãy xem xét:

template<typename Foo, typename T> T Bar(Foo f) { 
    return f(); 
} 

Trong trường hợp này, Bar có giá trị vô hiệu, nhưng cũng hợp lệ nếu thay đổi kiểu trả về. Tuy nhiên, nếu nó chỉ được gọi là f, thì mã này sẽ vỡ nếu T không có giá trị. Sử dụng return f(); cú pháp đảm bảo bảo tồn giá trị trả về của Foo() nếu có tồn tại, và cho phép void().

Ngoài ra, trả lại rõ ràng là một thói quen tốt để tham gia.

4

Templates:

template <typename T, typename R> 
R some_kind_of_wrapper(R (*func)(T), T t) 
{ 
    /* Do something interesting to t */ 
    return func(t); 
} 

int func1(int i) { /* ... */ return i; } 

void func2(const std::string& str) { /* ... */ } 

int main() 
{ 
    int i = some_kind_of_wrapper(&func1, 42); 

    some_kind_of_wrapper(&func2, "Hello, World!"); 

    return 0; 
} 

Nếu không có khả năng trả về void, các return func(t) trong mẫu sẽ không hoạt động khi nó được yêu cầu quấn func2.

0

Lý do trả về bộ nhớ như math.h luôn trả về. math.h không có khoảng trống và không có đối số trống. Có rất nhiều tình huống thực tế khi bạn cần bộ nhớ.

+0

Cái gì?Các hàm toán học lấy các đối số và trả về các giá trị bởi vì đó là những gì chúng cần làm là các hàm toán học ... – GManNickG

0

Có thể là trường hợp Foo() ban đầu trả lại giá trị, nhưng sau đó được đổi thành void và người cập nhật nó không nghĩ rất rõ ràng.

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