2012-09-22 32 views
5

Tôi đang cố gắng cung cấp một hàm gọi là lambda được cung cấp và tôi tự hỏi liệu có thể trả về giá trị mặc định nếu hàm trả về loại void hay không.Bất kỳ cách nào để khớp với giá trị trả về trong C++ 11?

Dưới đây là những gì tôi có cho đến nay, một hàm trả về giá trị trả về của lambda, nhưng nếu lambda là void, sau đó nó sẽ trả về 20.

#include <functional> 
#include <iostream> 

template <typename H> 
auto f(H&& h) -> decltype(h(), void()) 
{ 
    return h(); 
} 

template <typename H> 
auto f(H&& h) -> decltype(h(), int()) 
{ 
    h(); 
    return 20; 
} 

int main() 
{ 
    int r = f([](){ std::cout << "test1" << std::endl; return 10; }); // error here 
    std::cout << "r: " << r << std::endl; 
    r = f([](){ std::cout << "test2" << std::endl; }); 
    std::cout << "r: " << r << std::endl; 

    return 0; 
} 

này tạo ra các lỗi,

test.cpp:20:68: error: call of overloaded ‘f(main()::<lambda()>)’ is ambiguous 

Vì vậy, rõ ràng đây chỉ là do C++ không thể sử dụng đa hình dựa trên kiểu trả về. Tuy nhiên, tôi tự hỏi nếu có bất kỳ thủ thuật C++ 11 tốt, chẳng hạn như sử dụng tốt hơn của decltype hoặc một số ma thuật mẫu, có thể làm cho điều này có thể? Tôi yêu cầu bởi vì theo như tôi có thể thấy không có sự mơ hồ thực sự ở đây .. trình biên dịch suy ra loại trả về void và sau đó nói rằng nó không rõ ràng có khớp với phiên bản int hoặc void của f, một chút ngớ ngẩn.

Lý do để làm điều này là nếu hàm f mong đợi giá trị trả lại nhưng người dùng cung cấp lambda không bao gồm câu lệnh return, trình biên dịch sẽ nhập loại void và lỗi. Vì trong kịch bản thực, tôi có ý tưởng tốt về giá trị trả về mặc định hợp lý nên khi người dùng không quan tâm đến việc cung cấp giá trị, tôi tự hỏi liệu có thể có trình biên dịch cho phép người dùng bỏ qua câu lệnh thường gặp không cần thiết return cho thuận tiện.

Cảm ơn. Tôi nên đề cập rằng tôi đang sử dụng GCC 4.6.3.

trả lời: dựa trên gợi ý của việc sử dụng enable_if Xéo, tôi đã đưa ra những điều sau đây, mà dường như làm việc:

template <typename H> 
auto f(H&& h) -> typename std::enable_if<std::is_same<decltype(h()), void>::value, int>::type 
{ 
    h(); 
    return 20; 
} 

template <typename H> 
auto f(H&& h) -> typename std::enable_if<std::is_same<decltype(h()), int>::value, int>::type 
{ 
    return h(); 
} 

Cảm ơn!

+0

bạn đã thử nghiệm f trên các chức năng bình thường không? – CharlesB

+0

Có, trên các chức năng bình thường, nó cũng không rõ ràng. – Steve

+0

Tham số thứ hai của 'decltype': Tôi có thể hỏi nó là gì? (Thực sự, bởi vì tôi không biết!). – 0x499602D2

Trả lời

3

Bạn có thể sử dụng lệnh std :: enable_if.

Loại trả về của bạn sẽ là std::enable_if<!std::is_same<decltype(h()), void>::value, decltype(h())>:type cho loại đầu tiên và std::enable_if<std::is_same<decltype(h()), void>::value, int>::type cho loại thứ hai. Điều đó sẽ giúp mã của bạn hoạt động. Tôi đã không thử nghiệm nó, vì vậy tôi không chắc chắn nếu nó hoạt động đầy đủ.

+0

Tôi sợ rằng vẫn trả về lỗi "không rõ ràng". – Steve

+0

@Steve: Không, tính năng này hoạt động chính xác. Tôi nghĩ bạn có thể có lỗi đánh máy ở đâu đó. Xem [this] (http://liveworkspace.org/code/e0c94a11d120300743e202f4daec8a66). – Xeo

+0

@Xeo: Ah, cảm ơn, tôi nghĩ rằng thứ hai 'decltype (h())' trong phần đầu tiên của giải pháp JKor là vấn đề, vì nó đã thay đổi giá trị trả về cho 'f()'. Tôi đã làm việc dựa trên các ví dụ của bạn, tôi sẽ đăng mã trong câu hỏi. – Steve

2

Cho tôi lý do tại sao trình biên dịch có thể suy ra lý do tại sao quá tải nào phải chọn dựa trên những gì bạn làm bên trong hàm? Trong C++, độ phân giải quá tải chỉ quan tâm nếu mọi đối số đều phù hợp với tham số. Loại trả về và nội dung của hàm không quan tâm những gì-so-bao giờ.

As STL says:

TLDR: Templates là tham lam! Đừng quá tải chúng trừ khi bạn hoàn toàn chắc chắn điều gì sẽ xảy ra.

Và tham chiếu chung (template<class T> void f(T&&);) làm tham số là tham lam nhất mà bạn có thể nhận được.

Bạn có thể giải quyết nó như @JKor nói với SFINAE, nhưng đơn giản:

#include <type_traits> 

template<class F> 
auto f(F f) 
    -> decltype(true? f() : void()) 
{ 
    f(); 
} 

template <class F> 
auto f(F f) -> decltype(int(f())) 
{ 
    f(); 
    return 42; 
} 

int main(){ 
    f([]{}); 
} 

Lưu ý rằng GCC 4.7 có một lỗi nơi decltype(int(void_returning_function())) không gây các chức năng để SFINAE ra. Clang 3.1 một cách chính xác làm cho

f([]{}); 

làm việc, là tốt như

f([]{ return 42; }); 
Các vấn đề liên quan