लेशेंको का जवाब वास्तव में अच्छा है - पूरी तरह से: foo
उदाहरण जीसीसी के साथ संकलित नहीं करता है, जो कि विफल रहता है foo(7)
, FIRST
मैक्रो और वास्तविक फ़ंक्शन कॉल पर ठोकर खा रहा है (और (_1, __VA_ARGS__)
, एक अधिशेष अल्पविराम के साथ शेष है। इसके अतिरिक्त, हम मुसीबत में हैं अगर हम अतिरिक्त अधिभार प्रदान करना चाहते हैं। , जैसे foo(double)
।
इसलिए मैंने उत्तर को थोड़ा और विस्तृत करने का फैसला किया, जिसमें एक शून्य अधिभार की अनुमति देना भी शामिल है ( foo(void)
- जिससे काफी परेशानी हुई ...)।
आइडिया अब है: विभिन्न मैक्रो में एक से अधिक जेनेरिक को परिभाषित करें और तर्कों की संख्या के अनुसार सही एक का चयन करें!
इस उत्तर के आधार पर तर्कों की संख्या काफी आसान है :
#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)
#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y
यह अच्छा है, हम SELECT_1
या तो या SELECT_2
(या अधिक तर्क, यदि आप चाहते हैं / उनकी आवश्यकता है) का समाधान करते हैं, तो हमें बस उचित परिभाषित करने की आवश्यकता है:
#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1), \
int: foo_int, \
char: foo_char, \
double: foo_double \
)
#define SELECT_2(_1, _2) _Generic((_1), \
double: _Generic((_2), \
int: foo_double_int \
) \
)
ठीक है, मैंने पहले ही शून्य अधिभार जोड़ दिया है - हालांकि, यह वास्तव में सी मानक द्वारा कवर नहीं किया गया है, जो खाली वैरेडिक तर्कों को अनुमति नहीं देता है, अर्थात हम फिर संकलक एक्सटेंशन पर भरोसा करते हैं !
बहुत पहले, एक खाली मैक्रो कॉल ( foo()
) अभी भी एक टोकन का उत्पादन करता है, लेकिन एक खाली। इसलिए मैक्रो मैक्रो वास्तव में खाली मैक्रो कॉल पर भी 0 के बजाय 1 रिटर्न करता है। हम इस समस्या को "आसानी से" समाप्त कर सकते हैं, यदि हम __VA_ARGS__
सशर्त रूप से सूची खाली होने या न होने के आधार पर अल्पविराम लगाते हैं:
#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)
यह आसान लग रहा था , लेकिन COMMA
मैक्रो काफी भारी है; सौभाग्य से, विषय पहले से ही जेन्स गुस्तेद (धन्यवाद, जेन्स) के एक ब्लॉग में शामिल है । मूल चाल यह है कि फ़ंक्शन मैक्रोज़ का विस्तार नहीं किया जाता है, यदि कोष्ठक द्वारा पालन नहीं किया जाता है, तो आगे की व्याख्या के लिए, जेन्स के ब्लॉग पर एक नज़र डालें ... हमें केवल मैक्रोज़ को अपनी आवश्यकताओं को थोड़ा संशोधित करना होगा (मैं छोटे नामों का उपयोग करने जा रहा हूं) और संक्षिप्तता के लिए कम तर्क)।
#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, _3, N, ...) N
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 1, 0)
#define SET_COMMA(...) ,
#define COMMA(...) SELECT_COMMA \
( \
HAS_COMMA(__VA_ARGS__), \
HAS_COMMA(__VA_ARGS__ ()), \
HAS_COMMA(SET_COMMA __VA_ARGS__), \
HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)
#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3
#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
// ... (all others with comma)
#define COMMA_1111 ,
और अब हम ठीक हैं ...
एक ब्लॉक में पूरा कोड:
/*
* demo.c
*
* Created on: 2017-09-14
* Author: sboehler
*/
#include <stdio.h>
void foo_void(void)
{
puts("void");
}
void foo_int(int c)
{
printf("int: %d\n", c);
}
void foo_char(char c)
{
printf("char: %c\n", c);
}
void foo_double(double c)
{
printf("double: %.2f\n", c);
}
void foo_double_int(double c, int d)
{
printf("double: %.2f, int: %d\n", c, d);
}
#define foo(...) SELECT(__VA_ARGS__)(__VA_ARGS__)
#define SELECT(...) CONCAT(SELECT_, NARG(__VA_ARGS__))(__VA_ARGS__)
#define CONCAT(X, Y) CONCAT_(X, Y)
#define CONCAT_(X, Y) X ## Y
#define SELECT_0() foo_void
#define SELECT_1(_1) _Generic ((_1), \
int: foo_int, \
char: foo_char, \
double: foo_double \
)
#define SELECT_2(_1, _2) _Generic((_1), \
double: _Generic((_2), \
int: foo_double_int \
) \
)
#define ARGN(...) ARGN_(__VA_ARGS__)
#define ARGN_(_0, _1, _2, N, ...) N
#define NARG(...) ARGN(__VA_ARGS__ COMMA(__VA_ARGS__) 3, 2, 1, 0)
#define HAS_COMMA(...) ARGN(__VA_ARGS__, 1, 1, 0)
#define SET_COMMA(...) ,
#define COMMA(...) SELECT_COMMA \
( \
HAS_COMMA(__VA_ARGS__), \
HAS_COMMA(__VA_ARGS__ ()), \
HAS_COMMA(SET_COMMA __VA_ARGS__), \
HAS_COMMA(SET_COMMA __VA_ARGS__ ()) \
)
#define SELECT_COMMA(_0, _1, _2, _3) SELECT_COMMA_(_0, _1, _2, _3)
#define SELECT_COMMA_(_0, _1, _2, _3) COMMA_ ## _0 ## _1 ## _2 ## _3
#define COMMA_0000 ,
#define COMMA_0001
#define COMMA_0010 ,
#define COMMA_0011 ,
#define COMMA_0100 ,
#define COMMA_0101 ,
#define COMMA_0110 ,
#define COMMA_0111 ,
#define COMMA_1000 ,
#define COMMA_1001 ,
#define COMMA_1010 ,
#define COMMA_1011 ,
#define COMMA_1100 ,
#define COMMA_1101 ,
#define COMMA_1110 ,
#define COMMA_1111 ,
int main(int argc, char** argv)
{
foo();
foo(7);
foo(10.12);
foo(12.10, 7);
foo((char)'s');
return 0;
}