2014-09-17 20 views
10

Tôi có vấn đề sau đây mà tôi không thấy giải pháp thích hợp (và có thể không có giải pháp nào): Tôi có phương thức được tô điểm khi kiểu trả về phụ thuộc vào đầu vào loại và nhờ C++ 11 decltype loại trả về có thể lấy được dễ dàng, nhưng Tôi cũng muốn cho phép người dùng xác định loại trả về một cách rõ ràng nếu muốn.Mẫu chức năng C++: Loại trả về có nguồn gốc và rõ ràng

Chính thức hơn tôi có chức năng templated f, mà tôi muốn được gọi là f(x), không có đầu vào cũng như kiểu trả về được xác định rõ ràng. Và tôi cũng muốn có thể gọi nó là f<ret_t>x() với kiểu trả về được xác định rõ ràng, nhưng kiểu đầu vào vẫn được tạo tự động.

Bây giờ, đáp ứng các hạn chế đầu tiên với C++ 11 là dễ dàng (chúng ta hãy giả sử có một phương pháp khác templated:

template<typename InT> 
auto f(const InT& in) -> decltype(/* code deriving the return type using in */); 

Nhưng điều này sẽ không cho phép trọng của kiểu trả về, cho rằng tôi sẽ phải bổ sung nó như một tham số mẫu thứ hai và di chuyển các nguồn gốc decltype vào mẫu định nghĩa và có lẽ cần phải sử dụng std::declval<InT> hoặc std::result_of:

template< 
    typename InT, 
    typename RetT = /* code deriving return type using InT and declval/result_of */> 
RetT f(const InT& in); 

Tuy nhiên, cách này tôi luôn luôn cần phải cũng rõ ràng d efine InT khi gọi f. Vì vậy, việc kê khai của f để có thể để lại InT mở nhưng rõ RetT nên là:

template< 
    typename RetT = /* code deriving return type using InT and declval/result_of */, 
    typename InT> 
RetT f(const InT& in); 

Nhưng vì tại điểm mà tôi cần phải xác định một giá trị mặc định cho RetT, InT là chưa có sẵn và do đó không thể được sử dụng.

Cách giải quyết tốt nhất tôi có thể đưa ra cho đến nay, điều này không thỏa mãn và dường như không hoạt động vì việc khấu trừ RetT không thành công (rõ ràng là bạn không thể suy ra loại từ đối số mặc định), là:

template<typename RetT, typename InT> 
RetT f(
    const InT& in, 
    const RetT& = std::declval</* code deriving return type using InT or in and declval/result_of */>()); 

có cách nào tốt hơn để có một giá trị mặc định cho RetT đó là phụ thuộc vào InT khi vẫn có thể xác định rõ ràng RetT nếu mong muốn? Điều quan trọng cần lưu ý là kiểu trả về cần có sẵn trong việc thực hiện hàm để đối tượng của RetT được cấp phát trực tiếp và chỉ một lần bên trong thân phương thức.

+0

Dòng cuối cùng được chia theo hai cách: bạn không thể ODR sử dụng 'declval' và bạn không thể suy ra từ một đối số mặc định. –

+0

@Niall: Có, 'result_of' có thể hoạt động. Nhưng vấn đề là về thứ tự của các đối số trong trường hợp đó. –

+0

@ T.C.: Bây giờ bạn đề cập đến nó, có bạn không thể suy ra từ một đối số mặc định. Tôi sẽ đề cập đến điều này. –

Trả lời

10

Bạn có thể sử dụng std::conditional và loại dummy để kiểm tra xem chức năng có loại suy luận tự động hay loại người dùng đã chọn.

Nếu người dùng chọn loại trả về một cách rõ ràng, kiểu trả về sẽ khác với loại dummy và đây sẽ là kiểu trả về của hàm. Nếu không, chỉ cần sử dụng loại suy luận như trước đây.

Sau một ví dụ về việc sử dụng:

#include <typeindex> 
#include <type_traits> 
#include <iostream> 

struct dummy 
{ 
}; 

template<typename RetType = dummy, typename T> 
auto f(const T& in) 
-> typename std::conditional<std::is_same<RetType, dummy>::value, T, RetType>::type 
{ 
    std::cout<<typeid(RetType).name()<<" "<<typeid(T).name()<<std::endl; 
    return in; 
} 

int main() 
{ 
    f(1); 
    f<float>(1); 
} 
+0

Có lẽ thậm chí không cần sử dụng 'dummy' -' void' là đủ khả năng. –

+0

@ T.C. Nếu người dùng chọn void làm kiểu trả về, kiểu suy luận tự động sẽ được sử dụng. Tôi không nghĩ rằng điều này là mong muốn – Felics

+0

Một đối số mẫu mặc định trước những người không mặc định ... Tôi không biết điều này. Điều này thật tuyệt. – Niall

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