2016-06-16 14 views
7

* Không được nhầm lẫn với việc có liên quan đến mảng liên kết.Gọi một chức năng liên kết * với C Macro

Tôi biết cách vector hóa một hàm trong C bằng các macro để cho kết quả tương tự với chức năng Bản đồ (hoặc Áp dụng) của Mathematica. Cụ thể áp dụng một hàm vào danh sách các đối số.

#define Apply(type, function, ...)    \ 
{            \ 
    void *Stop = (int[]){0};      \ 
    type **List = (type*[]){__VA_ARGS__, Stop}; \ 
    for(int i = 0; List[i] != Stop; ++i)  \ 
    function(List[i]);       \ 
}      

Sau đó tôi có thể làm điều gì đó như

#define FreeAllAtOnce(...) Apply(void, free, __VA_ARGS__); 

mà có hiệu quả mà

free(Array1); 
free(Array2); 
free(Array3); 

tương đương với

FreeAllAtOnce(Array1, Array2, Array3); 

Tôi không làm cho điều đó lên, Tôi đọc về nó trong một cuốn sách và đã sử dụng nó háo hức kể từ đó.

Câu hỏi của tôi là: Tôi có thể làm điều gì đó tương tự như kết hợp một mảng thông qua một số chức năng nhị phân hay không. Ví dụ, lấy hàm GCD. Tôi muốn có một chức năng như:

GCD_all(a, b, c, d, e); 

đó có tác dụng tương tự như

GCD(GCD(GCD(GCD(a, b), c), d), e); 

cho bất kỳ số lượng đối số.

Tôi đã cố gắng làm điều này và không thể làm cho nó hoạt động đúng cách. Tôi cũng quan tâm đến trường hợp có thể có các tham số bổ sung được truyền cho hàm. Theo nghĩa chung nhất mà tôi đang tìm cách để làm điều này với các chức năng như:

Atype BinaryCombine(Atype a, Atype b, OtherType z, OtherType y) 

vì vậy mà tôi có một hàm

Atype BinaryCombineAll(Atype a, Atype b, Atype c, Atype d, OtherType z, OtherType y) 

Tôi hy vọng rằng có ý nghĩa. Bất kỳ ý tưởng hoặc trợ giúp nào cũng sẽ được đánh giá cao!

Cảm ơn.

+0

Tôi nghĩ rằng bạn có thể đã có một số thành công với C++ 11 Mẫu variadic – ForceBru

+0

BTW, làm thế nào bạn sẽ xác định có bao nhiêu đối số 'function' có thể mất? – ForceBru

+0

@ForceBru, tôi quan tâm đến việc ở trong phạm vi C. Trong chức năng ví dụ đầu tiên của tôi chỉ có một đối số. Những gì tôi yêu cầu là một trong đó có hai (hoặc nhiều hơn). – amcalde

Trả lời

2

Điều này đòi hỏi máy móc khá phức tạp (xem answer này để biết thêm chi tiết), vì bạn không thể thường có macro đệ quy trong C:

#define _NUM_ARGS2(X,X5,X4,X3,X2,X1,N,...) N 
#define NUM_ARGS(...) _NUM_ARGS2(0,__VA_ARGS__,5,4,3,2,1,0) 
// be sure to add X6,X7,... and 6,7,... to support more arguments 

#define GCD_OF_1(a)   (a)   
#define GCD_OF_2(a,b)  GCD(a, b) 
#define GCD_OF_3(a,b,...) GCD_OF_2(GCD_OF_2(a,b),__VA_ARGS__) 
#define GCD_OF_4(a,b,...) GCD_OF_3(GCD_OF_2(a,b),__VA_ARGS__) 
#define GCD_OF_5(a,b,...) GCD_OF_4(GCD_OF_2(a,b),__VA_ARGS__) 
// in general: 
// #define GCD_OF_N(a,b,...) GCD_OF_N-1(GCD_OF_2(a,b),__VA_ARGS__) 

#define _GCD_OF_N3(N, ...) GCD_OF_ ## N(__VA_ARGS__) 
#define _GCD_OF_N2(N, ...) _GCD_OF_N3(N, __VA_ARGS__) // helper macro to expand N 
#define GCD_all(...)  _GCD_OF_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__) 

int main(void) 
{ 
    GCD_all(a, b, c, d, e); 
} 

Các gcc -E sản xuất đầu ra như:

int main(void) 
{ 
    GCD(GCD(GCD(GCD(a, b), c), d), e); 
} 

Các NUM_ARGS tự động tìm số lượng đối số. Bằng cách này, bạn có được macro "điểm bắt đầu" GCD_OF_N để mở rộng thêm.

+0

Cảm ơn. Có vẻ như bạn sẽ cần phải thực hiện tất cả các macro này trước, bao gồm mọi trường hợp đầu vào có thể có. Tôi nghĩ về một cách khác để làm điều đó nhưng nó đòi hỏi tất cả các yếu tố đầu vào là con trỏ, không phải dữ liệu. – amcalde

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