2015-04-01 58 views
5

Tôi có hàm trả về hàm std :: cùng loại với hàm đó. Về cơ bản tôi muốn một cái gì đó như thế này:Loại hàm trả về trả về hàm std :: function

using RetType = std::function<RetType(void)>; 

mà rõ ràng sẽ không biên dịch. Làm cách nào để khai báo chính xác kiểu trả về?

+1

hiện đang sử dụng công cụ 'tự động'? – dwcanillas

+0

@dwcanillas: Giống như trong [câu hỏi này] (http://stackoverflow.com/q/25338795/596781)? –

+0

Um, tôi không chắc mình hiểu cách sử dụng tự động trong trường hợp này. Tôi phải khai báo kiểu và sau đó tự định nghĩa hàm này. –

Trả lời

4

Bạn không thể sử dụng std::function theo cách đó.

Bạn có thể tự cuộn, nhưng sẽ mất một số công việc.

Đây là một phác thảo:

template<class T, class A, class B> 
struct sub{using type=T;}; 
template<class T, class A, class B> 
using sub_t=typename sub<T,A,B>::type; 
template<class T, class B> 
struct sub<T,T,B>{using type=B;}; 
template<class R,class...Args,class A,class B> 
struct sub<R(Args...),A,B>{ 
    using type=sub_t<R,A,B>(sub_t<Args,A,B>...); 
}; 

viết ở trên. Nó có loại T và nếu nó khớp với A, nó trả về B. Nếu không, nó sẽ trả lại T. Nó cũng hoạt động trên các chữ ký chức năng.

Chúng ta có thể sử dụng điều này với một 'cờ' gõ vào một chữ ký để thay thế với các loại đối tượng chức năng chính:

struct recurse{}; // flag type 

// not needed in C++14: 
template<class Sig> 
using result_of_t=typename std::result_of<Sig>::type; 

template<class Sig> 
struct func { 
    using Sig2=sub_t<Sig,recurse,func>; 
    using function = std::function<Sig2>; 
    function impl; 
    template<class...Ts> 
    result_of_t<function const&(Ts...)> 
    operator()(Ts&&...ts)const 
    { 
    return impl(std::forward<Ts>(ts)...); 
    } 
}; 

Sau đó func<recurse()> là một đối tượng hàm rằng khi gọi, trả về một func<recurse()>.

Thực hiện việc triển khai đơn giản như lưu trữ std::function<Sig2> và gọi điện. Đoạn mã trên thiếu đánh bóng - bạn muốn nhà thầu, nhiều nhà khai thác, bảo mật, vv

live example

Lưu ý rằng một y-combinator có thể có ích nếu bạn muốn tránh phải chụp một bản sao của chính mình bằng cách tham chiếu để trả về *this trong một lambda, khi chụp bằng tham chiếu ngụ ý một thời gian giới hạn (và tránh sử dụng ptr được chia sẻ).

Công việc khác hữu ích sẽ được tăng cường sub để xử lý tham chiếu đến A hoặc thậm chí các mẫu chứa A làm đối số. (thuật toán phụ chung không thể thực hiện được trong C++, vì C++ không có khả năng siêu mẫu đầy đủ, nhưng việc xử lý mọi lớp mẫu hiện tại trong std rất dễ dàng: chúng đều là các mẫu kiểu thuần túy, hoặc std::array).


Để hoàn chỉnh, bạn có thể thêm video này vào sub:

// optional stuff for completeness: 
template<class T,class A,class B> 
struct sub<T&,A,B>{ 
    using type=sub_t<T,A,B>&; 
}; 
template<class T,class A,class B> 
struct sub<T*,A,B>{ 
    using type=sub_t<T,A,B>*; 
}; 
template<template<class...>class Z,class... Ts,class A,class B> 
struct sub<Z<Ts...>,A,B>{ 
    using type=Z<sub_t<Ts,A,B>...>; 
}; 
template<template<class,size_t>class Z,class T,size_t n,class A,class B> 
struct sub<Z<T,n>,A,B>{ 
    using type=Z<sub_t<T,A,B>,n>; 
}; 
template<class T,size_t n,class A,class B> 
struct sub<T[n],A,B>{ 
    using type=sub_t<T,A,B>[n]; 
}; 
template<class T,class A,class B> 
struct sub<T[],A,B>{ 
    using type=sub_t<T,A,B>[]; 
}; 
template<class T,class A,class B> 
struct sub<T const,A,B>{ 
    using type=sub_t<T,A,B> const; 
}; 
template<class T,class A,class B> 
struct sub<T volatile const,A,B>{ 
    using type=sub_t<T,A,B> volatile const; 
}; 
template<class T,class A,class B> 
struct sub<T volatile,A,B>{ 
    using type=sub_t<T,A,B> volatile; 
}; 

Và nó hiện đang làm việc một cách đệ quy trên nhiều mẫu, trên mảng, tài liệu tham khảo, và con trỏ, và với các loại cv-đủ điều kiện. Điều này cho phép bạn viết một cái gì đó như:

func< std::vector<recurse>() > 

mà là một đối tượng hàm mà operator() trả về một func< std::vector<recurse>() >.

Lưu ý rằng quy trình này không hoàn toàn hoàn hảo, như thể some_template<recurse> không phải là bản trình bày mẫu hợp lệ, các bước trên sẽ không hoạt động. Một phiên bản lạ có các mẫu và đối số có khả năng được áp dụng, thì việc thay thế, sau đó là ứng dụng, sẽ được yêu cầu trong các trường hợp như vậy.

+0

Bạn có bản demo không? –

+0

@KerrekSB Tôi làm bây giờ. – Yakk