যুক্তি সংখ্যার উপর ওভারলোডিং ম্যাক্রো


183

আমার দুটি ম্যাক্রো FOO2এবং FOO3:

#define FOO2(x,y) ...
#define FOO3(x,y,z) ...

আমি FOOনিম্নলিখিত হিসাবে একটি নতুন ম্যাক্রো সংজ্ঞায়িত করতে চাই :

#define FOO(x,y) FOO2(x,y)
#define FOO(x,y,z) FOO3(x,y,z)

তবে এটি কাজ করে না কারণ ম্যাক্রোগুলি আর্গুমেন্টের সংখ্যার উপর ওভারলোড করে না।

পরিবর্তন ছাড়া FOO2এবং FOO3, কিছু উপায় ম্যাক্রো নির্ধারণ করতে হয় FOO(ব্যবহার __VA_ARGS__বা অন্যভাবে) ডিসপ্যাচিং একই এফেক্ট পেতে FOO(x,y)করতে FOO2, এবং FOO(x,y,z)করতে FOO3?


1
আমার খুব দৃ feeling় অনুভূতি আছে যে এর আগে বেশ কয়েকবার জিজ্ঞাসা করা হয়েছিল ... [আপডেট] যেমন এখানে
কেরেরেক এসবি

1
@ কেরেকএসবি: এটি সম্পর্কিত হতে পারে, অবশ্যই এটি অবশ্যই কোনও ডুপ নয়।
অ্যান্ড্রু তোমাজোস

না, সম্ভবত এটি নয়, তবে এই জাতীয় কিছু মাসে একবার আসে ...
কেরেরেক এসবি

সি ++ জন্য একই: stackoverflow.com/questions/3046889/... যেহেতু preprocessors হয় মূলত একই একই হওয়া উচিত: stackoverflow.com/questions/5085533/...
সিরো Santilli郝海东冠状病六四事件法轮功

উত্তর:


262

সাধারণ হিসাবে:

#define GET_MACRO(_1,_2,_3,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2)(__VA_ARGS__)

সুতরাং আপনার যদি এই ম্যাক্রোগুলি থাকে:

FOO(World, !)         # expands to FOO2(World, !)
FOO(foo,bar,baz)      # expands to FOO3(foo,bar,baz)

আপনি যদি একটি চতুর্থ চান:

#define GET_MACRO(_1,_2,_3,_4,NAME,...) NAME
#define FOO(...) GET_MACRO(__VA_ARGS__, FOO4, FOO3, FOO2)(__VA_ARGS__)

FOO(a,b,c,d)          # expeands to FOO4(a,b,c,d)

স্বাভাবিকভাবেই, আপনি সংজ্ঞায়িত যদি FOO2, FOO3এবং FOO4, আউটপুট সংজ্ঞায়িত ম্যাক্রো তাদের দ্বারা প্রতিস্থাপন করা হবে।


5
@ Uroc327 তালিকায় একটি 0-যুক্তি ম্যাক্রো যুক্ত করা সম্ভব, আমার উত্তর দেখুন।
augurar

7
মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও 2010 এ কাজ করে না, ভিএ_আরজিএস একক ম্যাক্রো আর্গুমেন্টে প্রসারিত বলে মনে হচ্ছে।
Étienne

9
পাওয়া এই উত্তর করতে এটা MSVC 2010 অধীনে কাজ
Étienne

8
যদি EXPAND@ আতিয়েনের লিঙ্কে উল্লিখিতভাবে কীভাবে ব্যবহার করতে হয় সে সম্পর্কে যদি কেউ বিভ্রান্ত হন তবে আপনি মূলত এটির GET_MACROমতো অনুরোধ করুন #define FOO(...) EXPAND(GET_MACRO(__VA_ARGS__, FOO3, FOO2, FOO1)(__VA_ARGS__))এবং এটি এমএসভিসি-তে সঠিক যুক্তির প্রান্তে প্রসারিত হওয়া উচিত।
vexe

3
লক্ষ্য করুন সি ++ 11, আপনি একটি সতর্কবার্তা পাবেন: ISO C++11 requires at least one argument for the "..." in a variadic macro। এটি ঠিক করার জন্য, এফইও (...) এর সংজ্ঞাতে শেষ পরমের পরে একটি অব্যবহৃত যুক্তি (বা এমনকি কেবলমাত্র কমা) যুক্ত করুন: #define FOO(...) GET_MACRO(__VA_ARGS__, FOO3, FOO2, UNUSED)(__VA_ARGS__)( দেখুন এটি কলিরুতে চালিত হয় )।
ধাতু

49

উপর যোগ করতে netcoder এর উত্তর , আপনি আসলে এই 0-যুক্তি ম্যাক্রো সঙ্গে জিসিসি সাহায্যে করতে পারেন, ##__VA_ARGS__এক্সটেনশন:

#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
#define FOO(...) GET_MACRO(_0, ##__VA_ARGS__, FOO2, FOO1, FOO0)(__VA_ARGS__)

1
এফইউ 1 এবং এফও 2 কে অনুমতি দেওয়া কি এফইও00 না করেই করা সম্ভব #define FOO0 _Pragma("error FOO0 not allowed")?
noɥʇʎԀʎzɐɹƆ

FOO0Qt + mingw32 এ কাজ করছেন না, কলটিFOO0FOO1
JustWe

খুব প্রতিশ্রুতিবদ্ধ এবং সহজ। তবে -std = c ++ 11 দিয়ে FOO0 এর জন্য কাজ করে না ... :-(
লেওনপ

1
আপনি যদি সি তে এটি করছেন এবং আপনি ব্যবহার করার চেষ্টা করেন -std=c99বা একই সমস্যা -std=c11। আপনার প্রয়োজন -std=gnu99বা -std=gnu11পরিবর্তে প্রয়োজন
মাইকেল মরোজেক

1
দেখা যাচ্ছে যে প্রতিস্থাপন _0, ##__VA_ARGS__সঙ্গে _0 __VA_OPT__(,) __VA_ARGS__এই কাজ করতে নতুন পথ।
Wrzlprmft

36

এখানে আরও সাধারণ সমাধান:

// get number of arguments with __NARG__
#define __NARG__(...)  __NARG_I_(__VA_ARGS__,__RSEQ_N())
#define __NARG_I_(...) __ARG_N(__VA_ARGS__)
#define __ARG_N( \
      _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
     _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
     _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
     _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
     _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
     _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
     _61,_62,_63,N,...) N
#define __RSEQ_N() \
     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

// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__)

// definition for FOO
#define FOO(...) VFUNC(FOO, __VA_ARGS__)

আপনার ফাংশন সংজ্ঞায়িত করুন:

#define FOO2(x, y) ((x) + (y))
#define FOO3(x, y, z) ((x) + (y) + (z))

// it also works with C functions:
int FOO4(int a, int b, int c, int d) { return a + b + c + d; }

এখন আপনি FOO2, 3 এবং 4 টি যুক্তি দিয়ে ব্যবহার করতে পারেন :

FOO(42, 42) // will use makro function FOO2
FOO(42, 42, 42) // will use makro function FOO3
FOO(42, 42, 42, 42) // will call FOO4 function

সীমাবদ্ধতা

  • কেবলমাত্র 63৩ টি আর্গুমেন্ট (তবে প্রসারণযোগ্য)
  • শুধুমাত্র জিসিসিতে কোনও যুক্তির জন্য কাজ করা সম্ভব নয়

ধারনা

এটি ডিফল্ট যুক্তিগুলির জন্য ব্যবহার করুন:

#define func(...) VFUNC(func, __VA_ARGS__)
#define func2(a, b) func4(a, b, NULL, NULL)
#define func3(a, b, c) func4(a, b, c, NULL)

// real function:
int func4(int a, int b, void* c, void* d) { /* ... */ }

এটি অসীম সংখ্যক যুক্তিযুক্ত কার্যের জন্য ব্যবহার করুন:

#define SUM(...) VFUNC(SUM, __VA_ARGS__)
#define SUM2(a, b) ((a) + (b))
#define SUM3(a, b, c) ((a) + (b) + (c))
#define SUM4(a, b, c) ((a) + (b) + (c) + (d))
// ...

পিএস: __NARG__লরেন্ট ডেনিয়াউ এবং রোল্যান্ড ইলিগ থেকে এখানে অনুলিপি করা হয়েছে: https://groups.google.com/group/comp.std.c/browse_thread/thread/77ee8c8f92e4a3fb/346fc464319b1ee5?pli=1




ম্যাক্রো __NARG_I_সম্পূর্ণ অপ্রয়োজনীয় এবং অতিরিক্ত অতিরিক্ত বলে মনে হচ্ছে। এটি কেবল একটি অতিরিক্ত পদক্ষেপ এবং বিভ্রান্তি যোগ করে। আমি এটা সম্পূর্ণরূপে মুছে ফেলার এবং মাত্র সংজ্ঞা সুপারিশ __NARG__হিসাবে পরিবর্তে: #define __NARG__(...) __ARG_N(__VA_ARGS__,__RSEQ_N())
গ্যাব্রিয়েল স্ট্যাপলস

বা যে কোনওরকমে প্রাক প্রসেসিং ভেঙে দেবে? আমি কিছু অনুপস্থিত করছি?
গ্যাব্রিয়েল স্ট্যাপলস

একই সাথে _VFUNC_: কেবল এটি মুছুন। তারপরে, এর পরিবর্তে _VFUNCহিসাবে সংজ্ঞায়িত করুন । #define _VFUNC(name, n) name##n#define _VFUNC(name, n) _VFUNC_(name, n)
গ্যাব্রিয়েল স্ট্যাপলস

15

আমি কেবল এটি নিজেই গবেষণা করছিলাম এবং আমি এটি এখানে এসেছি । ম্যাক্রোর মাধ্যমে সি ফাংশনগুলির জন্য লেখক ডিফল্ট যুক্তি সমর্থনটি যুক্ত করেছিলেন।

আমি নিবন্ধটি সংক্ষেপে সংক্ষেপে জানার চেষ্টা করব। মূলত, আপনাকে এমন ম্যাক্রো সংজ্ঞায়িত করতে হবে যা আর্গুমেন্টগুলি গণনা করতে পারে। এই ম্যাক্রো 2, 1, 0, বা যুক্তিগুলির যে কোনও পরিসীমা সমর্থন করতে পারে তা ফিরিয়ে দেবে। উদাহরণ:

#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)

এটির সাথে আপনাকে অন্য একটি ম্যাক্রো তৈরি করতে হবে যা একটি পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করে, যুক্তি গণনা করে এবং উপযুক্ত ম্যাক্রোকে কল করে। আমি আপনার উদাহরণ ম্যাক্রো নিয়েছি এবং নিবন্ধের উদাহরণের সাথে এটি সংযুক্ত করেছি। আমার কাছে FOO1 কল ফাংশন a () এবং FOO2 কল ফাংশন একটি আর্গুমেন্ট বি সহ রয়েছে (স্পষ্টতই, আমি এখানে সি ++ ধরে নিচ্ছি, তবে আপনি যে কোনও ক্ষেত্রে ম্যাক্রো পরিবর্তন করতে পারেন)।

#define FOO1(a) a();
#define FOO2(a,b) a(b);

#define _ARG2(_0, _1, _2, ...) _2
#define NARG2(...) _ARG2(__VA_ARGS__, 2, 1, 0)

#define _ONE_OR_TWO_ARGS_1(a) FOO1(a)
#define _ONE_OR_TWO_ARGS_2(a, b) FOO2(a,b)

#define __ONE_OR_TWO_ARGS(N, ...) _ONE_OR_TWO_ARGS_ ## N (__VA_ARGS__)
#define _ONE_OR_TWO_ARGS(N, ...) __ONE_OR_TWO_ARGS(N, __VA_ARGS__)

#define FOO(...) _ONE_OR_TWO_ARGS(NARG2(__VA_ARGS__), __VA_ARGS__)

সুতরাং আপনি যদি

FOO(a)
FOO(a,b)

প্রিপ্রসেসর এটি প্রসারিত করে

a();
a(b);

আমি নিবন্ধটি অবশ্যই সংযুক্ত করে পড়ব read এটি অত্যন্ত তথ্যবহুল এবং তিনি উল্লেখ করেছেন যে NARG2 খালি যুক্তি নিয়ে কাজ করবে না। তিনি এখানে এটি অনুসরণ ।


7

উপরের উত্তরের আরও কমপ্যাক্ট সংস্করণ এখানে । উদাহরণ সহ।

#include <iostream>
using namespace std;

#define OVERLOADED_MACRO(M, ...) _OVR(M, _COUNT_ARGS(__VA_ARGS__)) (__VA_ARGS__)
#define _OVR(macroName, number_of_args)   _OVR_EXPAND(macroName, number_of_args)
#define _OVR_EXPAND(macroName, number_of_args)    macroName##number_of_args

#define _COUNT_ARGS(...)  _ARG_PATTERN_MATCH(__VA_ARGS__, 9,8,7,6,5,4,3,2,1)
#define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9, N, ...)   N


//Example:
#define ff(...)     OVERLOADED_MACRO(ff, __VA_ARGS__)
#define ii(...)     OVERLOADED_MACRO(ii, __VA_ARGS__)

#define ff3(c, a, b) for (int c = int(a); c < int(b); ++c)
#define ff2(c, b)   ff3(c, 0, b)

#define ii2(a, b)   ff3(i, a, b)
#define ii1(n)      ii2(0, n)


int main() {
    ff (counter, 3, 5)
        cout << "counter = " << counter << endl;
    ff (abc, 4)
        cout << "abc = " << abc << endl;
    ii (3)
        cout << "i = " << i << endl;
    ii (100, 103)
        cout << "i = " << i << endl;


    return 0;
}

চালান:

User@Table 13:06:16 /c/T
$ g++ test_overloaded_macros.cpp 

User@Table 13:16:26 /c/T
$ ./a.exe
counter = 3
counter = 4
abc = 0
abc = 1
abc = 2
abc = 3
i = 0
i = 1
i = 2
i = 100
i = 101
i = 102

মনে রাখবেন যে উভয়ই রয়েছে _OVRএবং _OVR_EXPANDএটি অপ্রয়োজনীয় দেখতে পারে তবে প্রিপ্রোসেসরটির _COUNT_ARGS(__VA_ARGS__)অংশটি প্রসারিত করা প্রয়োজন , যা অন্যথায় স্ট্রিং হিসাবে বিবেচিত হয়।


আমি এই সমাধানটি পছন্দ করি। এটি শূন্য আর্গুমেন্ট গ্রহণ করে এমন একটি ওভারলোডেড ম্যাক্রো পরিচালনা করতে কী পরিবর্তন করা যেতে পারে?
অ্যান্ড্রু


2

এভেজেনি সার্জিভের উত্তর থেকে এখানে একটি স্পিন রয়েছে। এই এক হিসাবে শূন্য আর্গুমেন্ট ওভারলোডগুলি সমর্থন করে !

আমি জিসিসি এবং মিনজিডাব্লুয়ের সাথে এটি পরীক্ষা করেছি। এটি সি ++ এর পুরানো এবং নতুন সংস্করণগুলির সাথে কাজ করা উচিত। নোট করুন যে আমি এমএসভিসির পক্ষে এটির গ্যারান্টি দিচ্ছি না ... তবে কিছু টুইটের মাধ্যমে আমি নিশ্চিত যে এটির সাথেও কাজ করা যেতে পারে।

আমি এটি শিরোনামের ফাইলটিতে আটকানোর জন্য ফর্ম্যাটও করেছি (যাকে আমি macroutil.h বলেছি)। যদি আপনি এটি করেন তবে বৈশিষ্ট্যটির যা প্রয়োজন তাই আপনি কেবল এই শিরোলেখকে অন্তর্ভুক্ত করতে পারেন এবং বাস্তবায়নের সাথে জড়িত ঘৃণ্যতার দিকে তাকান না।

#ifndef MACROUTIL_H
#define MACROUTIL_H

//-----------------------------------------------------------------------------
// OVERLOADED_MACRO
//
// used to create other macros with overloaded argument lists
//
// Example Use:
// #define myMacro(...) OVERLOADED_MACRO( myMacro, __VA_ARGS__ )
// #define myMacro0() someFunc()
// #define myMacro1( arg1 ) someFunc( arg1 )
// #define myMacro2( arg1, arg2 ) someFunc( arg1, arg2 )
//
// myMacro();
// myMacro(1);
// myMacro(1,2);
//
// Note the numerical suffix on the macro names,
// which indicates the number of arguments.
// That is the REQUIRED naming convention for your macros.
//
//-----------------------------------------------------------------------------

// OVERLOADED_MACRO
// derived from: /programming/11761703/overloading-macro-on-number-of-arguments
// replaced use of _COUNT_ARGS macro with VA_NUM_ARGS defined below
// to support of zero argument overloads
#define OVERLOADED_MACRO(M, ...) _OVR(M, VA_NUM_ARGS(__VA_ARGS__)) (__VA_ARGS__)
#define _OVR(macroName, number_of_args)   _OVR_EXPAND(macroName, number_of_args)
#define _OVR_EXPAND(macroName, number_of_args)    macroName##number_of_args
//#define _COUNT_ARGS(...)  _ARG_PATTERN_MATCH(__VA_ARGS__, 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1)
#define _ARG_PATTERN_MATCH(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, N, ...)   N

// VA_NUM_ARGS
// copied from comments section of:
// http://efesx.com/2010/07/17/variadic-macro-to-count-number-of-arguments/
// which itself was derived from:
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define _ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15
#define HAS_COMMA(...) _ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define HAS_NO_COMMA(...) _ARG16(__VA_ARGS__, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
#define _TRIGGER_PARENTHESIS_(...) ,

#define HAS_ZERO_OR_ONE_ARGS(...) \
    _HAS_ZERO_OR_ONE_ARGS( \
    /* test if there is just one argument, eventually an empty one */ \
    HAS_COMMA(__VA_ARGS__), \
    /* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ \
    HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
    /* test if the argument together with a parenthesis adds a comma */ \
    HAS_COMMA(__VA_ARGS__ (~)), \
    /* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ \
    HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~)) \
    )

#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _HAS_ZERO_OR_ONE_ARGS(_0, _1, _2, _3) HAS_NO_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,

#define _VA0(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__)
#define _VA1(...) HAS_ZERO_OR_ONE_ARGS(__VA_ARGS__)
#define _VA2(...) 2
#define _VA3(...) 3
#define _VA4(...) 4
#define _VA5(...) 5
#define _VA6(...) 6
#define _VA7(...) 7
#define _VA8(...) 8
#define _VA9(...) 9
#define _VA10(...) 10
#define _VA11(...) 11
#define _VA12(...) 12
#define _VA13(...) 13
#define _VA14(...) 14
#define _VA15(...) 15
#define _VA16(...) 16

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, PP_RSEQ_N(__VA_ARGS__) )
#define VA_NUM_ARGS_IMPL(...) VA_NUM_ARGS_N(__VA_ARGS__)

#define VA_NUM_ARGS_N( \
    _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
    _11,_12,_13,_14,_15,_16,N,...) N

#define PP_RSEQ_N(...) \
    _VA16(__VA_ARGS__),_VA15(__VA_ARGS__),_VA14(__VA_ARGS__),_VA13(__VA_ARGS__), \
    _VA12(__VA_ARGS__),_VA11(__VA_ARGS__),_VA10(__VA_ARGS__), _VA9(__VA_ARGS__), \
    _VA8(__VA_ARGS__),_VA7(__VA_ARGS__),_VA6(__VA_ARGS__),_VA5(__VA_ARGS__), \
    _VA4(__VA_ARGS__),_VA3(__VA_ARGS__),_VA2(__VA_ARGS__),_VA1(__VA_ARGS__), \
    _VA0(__VA_ARGS__)

//-----------------------------------------------------------------------------

#endif // MACROUTIL_H

2

এটি জিসিসি, কলং এবং এমএসভিসির ক্ষেত্রে দুর্দান্ত কাজ করছে বলে মনে হচ্ছে। এটি এখানে কয়েকটি উত্তরের একটি সাফ সংস্করণ

#define _my_BUGFX(x) x

#define _my_NARG2(...) _my_BUGFX(_my_NARG1(__VA_ARGS__,_my_RSEQN()))
#define _my_NARG1(...) _my_BUGFX(_my_ARGSN(__VA_ARGS__))
#define _my_ARGSN(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,N,...) N
#define _my_RSEQN() 10,9,8,7,6,5,4,3,2,1,0

#define _my_FUNC2(name,n) name ## n
#define _my_FUNC1(name,n) _my_FUNC2(name,n)
#define GET_MACRO(func,...) _my_FUNC1(func,_my_BUGFX(_my_NARG2(__VA_ARGS__))) (__VA_ARGS__)

#define FOO(...) GET_MACRO(FOO,__VA_ARGS__)

1
@ রিয়ানকুইন এই ম্যাক্রোটিকে কীভাবে সামঞ্জস্য করবেন যাতে এটি শূন্য আর্গুমেন্টের সাথে কাজ করে #define func0() foo? দুর্ভাগ্যক্রমে বর্তমান সংস্করণটি এই কেসটি পরিচালনা করে না।
জেরি মা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.