Variadic وحدات الماكرو المعالج عودي - هل من الممكن؟

StackOverflow https://stackoverflow.com/questions/824639

  •  05-07-2019
  •  | 
  •  

سؤال

ولقد واجهت مشكلة نظرية قليلا. في قطعة من التعليمات البرمجية انا الحفاظ هناك مجموعة من وحدات الماكرو مثل

#define MAX_OF_2(a, b)       (a) > (b) ? (a) : (b)
#define MAX_OF_3(a, b, c)    MAX_OF_2(MAX_OF_2(a, b), c)
#define MAX_OF_4(a, b, c, d) MAX_OF_2(MAX_OF_3(a, b, c), d)
...etc up to MAX_OF_8

ما أود القيام به هو استبدالها بشيء من هذا القبيل:

/* Base case #1, single input */
#define MAX_OF_N(x)      (x)

/* Base case #2, two inputs */
#define MAX_OF_N(x, y)   (x) > (y) ? (x) : (y)

/* Recursive definition, arbitrary number of inputs */
#define MAX_OF_N(x, ...) MAX_OF_N(x, MAX_OF_N(__VA_ARGS__))

... وهذا، بالطبع، هو ليس رمز المعالج صالح.

<ط> تجاهل أن هذه الحالة بالذات ربما ينبغي حلها باستخدام وظيفة بدلا من ماكرو المعالج ، هل من الممكن لتحديد ماكرو MAX_OF_N variadic ()؟

وفقط من أجل الوضوح، وينبغي أن تكون النتيجة النهائية ماكرو واحد أن يأخذ عدد التعسفي من المعلمات وتقييم لأكبر منهم. لقد حصلت على الشعور الغريب أن هذا ينبغي أن يكون ممكنا، ولكن أنا لا نرى كيف.

هل كانت مفيدة؟

المحلول

لا، لأن يستغرق سوى المعالج "انتقاد" واحدة على الملف. ليس هناك طريقة للحصول عليه لتحديد متكرر وحدات الماكرو.

والرمز الوحيد الذي رأيته يفعل شيئا من هذا القبيل كان <م> لا variadic، ولكنها تستخدم القيم الافتراضية زيارتها المستخدم لتمرير:

x = MAX_OF_8 (a, b, -1, -1, -1, -1, -1, -1)

وعلى افتراض أن كل قيم غير سلبية.

يجب

وظائف مضمنة تعطيك الشيء نفسه بالنسبة C ++ على الأقل. كما تصرح، هو على الأرجح أفضل اليسار إلى وظيفة مع الحجج المتغيرة مماثلة لprintf().

نصائح أخرى

ومن الممكن كتابة ماكرو يتم تقييمها إلى عدد من الحجج يسمى معها. (لم أتمكن من العثور على وصلة إلى المكان الذي رأيت لأول مرة.) لذلك يمكن أن تكتب MAX_OF_N () من شأنها أن تعمل ما تريد، ولكن كنت لا تزال في حاجة إلى كل وحدات الماكرو مرقمة حتى بعض الحد:

#define MAX_OF_1(a)         (a)         
#define MAX_OF_2(a,b)       max(a, b)

#define MAX_OF_3(a,...)    MAX_OF_2(a,MAX_OF_2(__VA_ARGS__))
#define MAX_OF_4(a,...)    MAX_OF_2(a,MAX_OF_3(__VA_ARGS__))
#define MAX_OF_5(a,...)    MAX_OF_2(a,MAX_OF_4(__VA_ARGS__))
...
#define MAX_OF_64(a,...)   MAX_OF_2(a,MAX_OF_63(__VA_ARGS__))

// NUM_ARGS(...) evaluates to the literal number of the passed-in arguments.
#define _NUM_ARGS2(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N
#define NUM_ARGS(...) _NUM_ARGS2(0, __VA_ARGS__ ,64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49,48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define _MAX_OF_N3(N, ...) MAX_OF_ ## N(__VA_ARGS__)
#define _MAX_OF_N2(N, ...) _MAX_OF_N3(N, __VA_ARGS__)
#define MAX_OF_N(...)      _MAX_OF_N2(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)

والآن MAX_OF_N(a,b,c,d,e) سيقيم لmax(a, max(b, max(c, max(d, e)))). (لقد اختبرت في دول مجلس التعاون الخليجي 4.2.1).

لاحظ أن من المهم جدا أن القضية الأساسية (MAX_OF_2) لا يعيد حججها أكثر من مرة واحدة في التوسع (والذي هو السبب في أنني وضعت max في هذا المثال). خلاف ذلك، تريد ان تكون مضاعفة طول التوسع لكل مستوى، لذلك يمكنك أن تتخيل ماذا سيحدث مع 64 الحجج:)

هل يمكن النظر في هذا الغش، لأنها ليست متكررة وأنها لا تفعل العمل في المعالج. ويستخدم امتداد دول مجلس التعاون الخليجي. وأنها لا تعمل إلا لنوع واحد. غير أنه، ماكرو MAX_OF_N variadic:

#include <iostream>
#include <algorithm>

#define MAX_OF_N(...) ({\
        int ra[] = { __VA_ARGS__ }; \
        *std::max_element(&ra[0], &ra[sizeof(ra)/sizeof(int)]); \
    })

int main() {
    int i = 12;
    std::cout << MAX_OF_N(1,3,i,6);
}

وأوه نعم، وبسبب التعبير متغير المحتملين في قائمة مهيئ، وأنا لا أعتقد أن ما يعادل هذا (باستخدام وظيفة خاصة بها لتجنب الأمراض المنقولة جنسيا :: max_element) ستعمل في C89. لكنني لست متأكدا من وحدات الماكرو variadic هي في C89 سواء.

وهنا شيء وأعتقد أن يحصل حول "نوع واحد فقط" قيود. انها تحصل على شعر بعض الشيء، على الرغم من:

#include <iostream>
#include <algorithm>

#define MAX_OF_N(x, ...) ({\
        typeof(x) ra[] = { (x), __VA_ARGS__ }; \
        *std::max_element(&ra[0], &ra[sizeof(ra)/sizeof(ra[0])]); \
    })

int main() {
    int i = 12;
    std::cout << MAX_OF_N(i+1,1,3,6,i);
}

وأعتقد أنه حتى لو كنت قد توسيع وحدات الماكرو بشكل متكرر، لن يكون هناك مشكلة واحدة صغيرة مع نهجكم من حيث الكفاءة ... عندما يتم توسيع وحدات الماكرو، إذا كان MAX_OF_[N-1] أكبر، ثم لديك لتقييمها مرة أخرى من الصفر.

وهنا إجابة سخيفة وغبية انه من المحتمل ان أحدا لن يحب الانجاز

الملف "source.c"

#include "my_macros.h"
...

الملف "ماكيفيلي"

myprogram: source.c my_macros.h
 gcc source.c -o myprogram

my_macros.h: make_macros.py
 python make_macros.py > my_macros.h

الملف "make_macros.py"

def split(l):
    n = len(l)
    return l[:n/2], l[n/2:]

def gen_param_seq(n):
    return [chr(i + ord("A")) for i in range(n)]

def make_max(a, b):
    if len(a) == 1:
        parta = "("+a[0]+")"
    else:
        parta = make_max(*split(a))

    if len(b) == 1:
        partb = "("+b[0]+")"
    else:
        partb = make_max(*split(b))

    return "("+parta +">"+partb+"?"+parta+":"+partb+")"

for i in range(2, 9):
    p = gen_param_seq(i)
    print "#define MAX_"+str(i)+"("+", ".join(p)+") "+make_max(*split(p))

وبعد ذلك سيكون لديك تلك حدات الماكرو جميلة تعريف:

#define MAX_2(A, B) ((A)>(B)?(A):(B))
#define MAX_3(A, B, C) ((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))
#define MAX_4(A, B, C, D) (((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D)))
#define MAX_5(A, B, C, D, E) (((A)>(B)?(A):(B))>((C)>((D)>(E)?(D):(E))?(C):((D)>(E)?(D):(E)))?((A)>(B)?(A):(B)):((C)>((D)>(E)?(D):(E))?(C):((D)>(E)?(D):(E))))
#define MAX_6(A, B, C, D, E, F) (((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))>((D)>((E)>(F)?(E):(F))?(D):((E)>(F)?(E):(F)))?((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C))):((D)>((E)>(F)?(E):(F))?(D):((E)>(F)?(E):(F))))
#define MAX_7(A, B, C, D, E, F, G) (((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C)))>(((D)>(E)?(D):(E))>((F)>(G)?(F):(G))?((D)>(E)?(D):(E)):((F)>(G)?(F):(G)))?((A)>((B)>(C)?(B):(C))?(A):((B)>(C)?(B):(C))):(((D)>(E)?(D):(E))>((F)>(G)?(F):(G))?((D)>(E)?(D):(E)):((F)>(G)?(F):(G))))
#define MAX_8(A, B, C, D, E, F, G, H) ((((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D)))>(((E)>(F)?(E):(F))>((G)>(H)?(G):(H))?((E)>(F)?(E):(F)):((G)>(H)?(G):(H)))?(((A)>(B)?(A):(B))>((C)>(D)?(C):(D))?((A)>(B)?(A):(B)):((C)>(D)?(C):(D))):(((E)>(F)?(E):(F))>((G)>(H)?(G):(H))?((E)>(F)?(E):(F)):((G)>(H)?(G):(H))))

ووأفضل شيء هو أن ... يعمل ^ _ ^

إذا كنت تريد الذهاب في هذا الطريق في C ++، نلقي نظرة على قالب metaprogramming . انها ليست جميلة، وأنها قد لا يحل المشكلة بالضبط، ولكن سيكون التعامل مع العودية.

أولا، وحدات الماكرو لا توسيع recusrsively. وعلى الرغم من وحدات الماكرو يمكن أن يكون reentrance عن طريق إنشاء ماكرو لكل مستوى العودية ومن ثم استنتاج مستوى العودية. ومع ذلك، كل هذا التكرار واستنتاج العودية، يؤخذ من الرعاية من قبل في Boost.Preprocessor المكتبة. لذا يمكنك استخدام العليا أضعاف ماكرو لحساب الحد الأقصى:

#define MAX_EACH(s, x, y) BOOST_PP_IF(BOOST_PP_GREATER_EQUAL(x, y), x, y)
#define MAX(...) BOOST_PP_SEQ_FOLD_LEFT(MAX_EACH, 0, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) 

MAX(3, 6, 8) //Outputs 8
MAX(4, 5, 9, 2) //Outputs 9

والآن، وهذا فهم الأرقام حرفية بين 0-256. انها لن تعمل على المتغيرات C ++ أو التعبير، لأنه لا يفهم المعالج C ++ C. في استبدال نص مجرد محض. لكن C ++ يوفر ميزة تدعى "وظيفة" التي ستعمل على تعبيرات C ++، ويمكنك استخدامه لحساب قيمة الحد الأقصى.

template<class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

template<class X, class... T>
auto max(X x, T ... args) -> decltype(max(x, max(args...)))
{
    return max(x, max(args...));
}

والآن، رمز أعلاه لا تحتاج إلى مترجم C ++ 11. إذا كنت تستخدم C ++ 03، يمكنك إنشاء الزائدة متعددة من وظيفة من أجل محاكاة المعلمات variadic. وعلاوة على ذلك، يمكننا استخدام المعالج لتوليد هذا الرمز المتكررة بالنسبة لنا (أن يكون ما هو عليه هناك ل). وذلك في C ++ 03، يمكنك كتابة هذا:

template<class T>
T max(T x, T y)
{
    return x > y ? x : y;
}

#define MAX_FUNCTION(z, n, data) \
template<class T> \
T max(T x, BOOST_PP_ENUM_PARAMS(n, T x)) \
{ \
    return max(x, max(BOOST_PP_ENUM_PARAMS(n, x)));\
}

BOOST_PP_REPEAT_FROM_TO(2, 64, MAX_FUNCTION, ~) 
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top