2017-01-12 23 views
16

Giả sử tôi cóSử dụng các loại chức năng trong std :: chức năng để khai báo nhiều chức năng của loại hình đó

typedef std::function< 
    double(
     int, 
     long 
    ) 
> FooType; 

và tôi muốn tuyên bố nguyên mẫu hàm cho một loạt các chức năng mà tôi có thể khe cắm vào một std::function thuộc loại này. Tôi biết tôi có thể viết

double foo1(int, long); 
double foo2(int, long); 

vv, nhưng có cách nào tôi có thể sử dụng FooType bằng cách nào đó khi khai báo nguyên mẫu hàm? Một cái gì đó như

FooType::type foo1, foo2;

Có lẽ tôi có thể phải sử dụng (*foo1) hoặc tương tự? Đương nhiên trong việc thực hiện các chức năng tôi cần phải đánh vần nó ra tay dài vì vậy tôi có thể đưa vào một số thông số, nhưng viết nó như trên sẽ giữ cho tập tin tiêu đề của tôi sạch hơn.

Trả lời

18

Chắc chắn bạn có thể, chỉ như mọi khi *, sử dụng chuyên môn hóa từng phần:

template <typename> struct fn_sig; 
template <typename T> struct fn_sig<std::function<T>> { using type = T; }; 

Cách sử dụng:

fn_sig<FooType>::type f; 

double f(int a, long b) { return double(a)/b; } 

(Bạn sẽ rõ ràng là cần phải đánh vần các chức năng cơ bản gõ ra cho định nghĩa hàm .)



*) Có nghĩa là đây là câu trả lời tương tự cho bất kỳ câu hỏi nào của biểu mẫu "tôi có thể lấy thông số mẫu từ một mẫu đặc biệt" không.

+2

[Full demo] (https://ideone.com/5JPguy) –

+0

Và như thường lệ đối với một cái gì đó như thế này, nó có thể được đơn giản hóa với một mẫu bí danh: 'template sử dụng fn_sig_t = typename fn_sig :: type;' –

+0

wow tuyệt vời ... C++ đang trở nên kỳ lạ và tràn ngập hơn –

4

Bạn có thể dễ dàng làm điều này bằng cách tạo ra một mẫu struct mà destructures loại FooType, phù hợp với T trong std::function<T>:

template <typename T> 
struct destructure; 

template <typename T> 
struct destructure<std::function<T>> 
{ 
    using type = T; 
}; 

template <typename T> 
using destructure_t = typename destructure<T>::type; 

Sau đó, bạn có thể sử dụng destructure_t tuyên bố chức năng của bạn:

destructure_t<FooType> foo; 

int main() 
{ 
    foo(1, 20l); 
} 

Sau đó, bạn có thể xác định bằng cú pháp hàm thông thường:

double foo(int i, long l) 
{ 
    std::cout << i << " " << l << "\n"; 
    return 0; 
} 

main của bạn sẽ in "1 20".

wandbox example

0

Là một giải pháp thay thế cho một trong những công tác được trình bày bởi @KerrekSB, bạn có thể sử dụng một khai báo hàm và một bí danh như sau nếu bạn muốn nhận được một loại con trỏ:

#include <functional> 
#include <utility> 

template<typename F> F * get(std::function<F>); 
template<typename F> using FPtr = decltype(get(std::declval<F>())); 

double f(int, long) { return {}; } 

int main() { 
    using FooType = std::function<double(int, long)>; 
    FPtr<FooType> myF = f; 
    (void)myF; 
} 

Hoặc một phiên bản được sửa đổi đôi chút nếu bạn chỉ muốn loại thực tế:

#include <type_traits> 
#include <functional> 
#include <utility> 

template<typename F> F * get(std::function<F>); 
template<typename F> using MyType = typename std::remove_pointer<decltype(get(std::declval<F>()))>::type; 

double f(int, long) { return {}; } 

int main() { 
    using FooType = std::function<double(int, long)>; 
    MyType<FooType> *myF = f; 
    (void)myF; 
} 
8

viết nó như trên sẽ giữ cho phần đầu của tôi tập tin sạch hơn

Nó sẽ sạch hơn (với ít lập trình meta) để đi theo con đường khác xung quanh: Bắt đầu với việc kê khai foo() và tạo FooType từ nó.

double foo(int, long); 

typedef std::function< decltype(foo) > FooType; 

Vì có lẽ một số chức năng như vậy, hai typedefs có thể là bao thanh toán tối ưu:

typedef double FooFn(int, long); 
typedef std::function<FooFn> FooType; 

FooFn foo1, foo2, foo3; 

Tất nhiên, trong việc thực hiện (cpp) nộp chữ ký cần phải được viết longhand.

Một điều nữa, lưu ý rằng std::function là tổng quát nặng về các con trỏ hàm. Nếu bạn chỉ bao giờ gán các chức năng thông thường vào nó, một con trỏ hàm có thể tốt hơn và đây sẽ là một thay thế thả vào:

typedef FooFn * FooType; 
+0

Đây là một ý tưởng tuyệt vời nhưng một cái gì đó mà tôi bỏ qua từ câu hỏi là tôi có nhiều hàm 'foo' với cùng một chữ ký. Nhưng tôi sẽ upvote này, với lời xin lỗi của tôi. –

+1

@MichaelBullock Được ya bảo hiểm, xem chỉnh sửa tôi sắp đăng. – Potatoswatter

+1

'Nếu bạn chỉ bao giờ gán các hàm bình thường vào nó, một con trỏ hàm có thể tốt hơn' +1, với việc bổ sung lambdas vô nghĩa cũng có thể được biểu diễn bằng các hàm đơn giản. –

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