সি ++ প্রিপ্রসেসর __VA_ARGS__ আর্গুমেন্টের সংখ্যা


100

সাধারণ প্রশ্ন যার জন্য আমি নেটটিতে উত্তর খুঁজে পাই না। বৈকল্পিক আর্গুমেন্ট ম্যাক্রোগুলিতে, যুক্তির সংখ্যাটি কীভাবে খুঁজে পাবেন? আমি বুস্ট প্রিপ্রোসেসর সহ ঠিক আছি, যদি এর সমাধান থাকে।

যদি এটি কোনও পার্থক্য করে, আমি আরও পুনরায় প্রসেসের জন্য প্রিপ্রোসেসর সিকোয়েন্স, তালিকা বা অ্যারে বাড়ানোর জন্য ম্যাক্রো যুক্তিগুলির পরিবর্তনশীল সংখ্যাকে রূপান্তর করার চেষ্টা করছি।


কেবল পরিষ্কার করার জন্য - আপনি ভেরিয়াদিক ম্যাক্রোগুলি সম্পর্কে জিজ্ঞাসা করছেন, এবং ম্যাক্রোগুলি ভেরিয়াদিক সি কার্যকারিতা তৈরি করতে ব্যবহৃত হয়নি?

4
একই ধরণের যুক্তি কি? যদি তাই হয়, এবং যদি প্রকারটি জানা থাকে তবে যৌগিক আক্ষরিক মাধ্যমে একটি সি সি সমাধান রয়েছে; যদি এটি অজানা থাকে তবে আপনি __typeof__এটি কমপক্ষে কয়েকটি সংকলক
কাজিস্টেফ

4
যেহেতু আলোচনাটি বুস্ট প্রিপ্রোসেসর ক্রম ইত্যাদি সম্পর্কে, তাই এটি সি ++ হতে হবে (এজন্য আমি কিউকে পিছনে ফেলেছি - তবে প্রশ্নের শিরোনাম পরিবর্তন করতে ব্যর্থ হয়েছি) ... ওফস; আমি এটা ঠিক করব।
জোনাথন লেফলার

@ জোনাথনলফলার সত্য, বুস্ট একটি সি ++ গ্রন্থাগার। তবে বুস্ট.প্রসেসর প্রসেসরটি সি এএফআইএইকে ব্যবহার করা যেতে পারে, এটি ব্যবহার করে কিছুই সি ++ নির্দিষ্ট নয়।
জাস্টিন

উত্তর:


91

এটি আসলে সংকলক নির্ভর, এবং কোনও মানক দ্বারা সমর্থিত নয়।

এখানে তবে আপনার কাছে ম্যাক্রো বাস্তবায়ন রয়েছে যা গণনা করে:

#define PP_NARG(...) \
         PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#define PP_NARG_(...) \
         PP_ARG_N(__VA_ARGS__)
#define PP_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 PP_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

/* Some test cases */


PP_NARG(A) -> 1
PP_NARG(A,B) -> 2
PP_NARG(A,B,C) -> 3
PP_NARG(A,B,C,D) -> 4
PP_NARG(A,B,C,D,E) -> 5
PP_NARG(1,2,3,4,5,6,7,8,9,0,
         1,2,3,4,5,6,7,8,9,0,
         1,2,3,4,5,6,7,8,9,0,
         1,2,3,4,5,6,7,8,9,0,
         1,2,3,4,5,6,7,8,9,0,
         1,2,3,4,5,6,7,8,9,0,
         1,2,3) -> 63

.... তবে এখন সি ++ 0x এ স্ট্যান্ডার্ড এবং আরও অনেক আগে হওয়া উচিত ছিল কারণ এটি দূষিত কলগুলি থেকে ভারডিক ফাংশনগুলি রক্ষা করার দুর্দান্ত উপায়টিকে মঞ্জুরি দেয় (যেমন, আপনি ভারাদিক আইটেমগুলির পরে মানগুলি পাস করতে পারেন This এটি আসলে একটি উপায় আমি যে গণনাটি ব্যবহার
করতাম

উত্তর অন্য সাইটে লিঙ্ক। এছাড়াও লিঙ্কটি সঠিক উত্তরটির দিকে ইঙ্গিত করছে বলে মনে হচ্ছে না। এমনকি যদি আমি উদ্দেশ্যযুক্ত উত্তরটি সন্ধান করতে পারি তবে এটি একটি দুর্বল বলে মনে হচ্ছে কারণ এটি একটি হার্ডকোডযুক্ত "-1" এম্বেড করে যা সংকলিত হবে। আরও ভাল পদ্ধতি আছে।
ceztko

4
ধন্যবাদ! এটি আমার জন্য ভিজ্যুয়াল স্টুডিও 2013 এ কাজ করেছে: #define EXPAND(x) x #define PP_ARG_N(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N #define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, 9,8,7,6,5,4,3,2,1,0))`` `
মচিয়াসন

4
PP_NARG()0 ফিরে আসতে ব্যর্থ । সমাধান GET_ARG_COUNT()& Y_TUPLE_SIZE()কাজ কাজ।
পিএসকোকিক

4
" PP_NARG()0" ফিরে আসতে ব্যর্থ ... অগত্যা কোনও সমস্যা নয়। এক যে বলা PP_NARG() উচিত একই কারণে 1 ফিরে PP_NARG(,)2. ফেরত পাঠাবেন শনাক্তকারী 0 প্রকৃতপক্ষে কিছু ক্ষেত্রে কুশলী হতে পারে, কিন্তু সমাধান পারেন কম সাধারণ হবে বলে মনে হচ্ছে (আবশ্যক করার প্রথম টোকেন pasteable হতে; যা হতে পারে বা নাও হতে পারে হতে ঠিক আছে আপনি কীসের জন্য এটি ব্যবহার করছেন) তার উপর নির্ভর করে বা বাস্তবায়ন নির্দিষ্ট (যেমন gnu এর কমা-অপসারণ-পেস্ট কৌশল প্রয়োজন)।
এইচ ওয়াল্টার্স

101

আমি সাধারণত এই ম্যাক্রোটি বেশ কয়েকটি প্যারাম খুঁজে পেতে ব্যবহার করি:

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))

পুরো উদাহরণ:

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#define NUMARGS(...)  (sizeof((int[]){__VA_ARGS__})/sizeof(int))
#define SUM(...)  (sum(NUMARGS(__VA_ARGS__), __VA_ARGS__))

void sum(int numargs, ...);

int main(int argc, char *argv[]) {

    SUM(1);
    SUM(1, 2);
    SUM(1, 2, 3);
    SUM(1, 2, 3, 4);

    return 1;
}

void sum(int numargs, ...) {
    int     total = 0;
    va_list ap;

    printf("sum() called with %d params:", numargs);
    va_start(ap, numargs);
    while (numargs--)
        total += va_arg(ap, int);
    va_end(ap);

    printf(" %d\n", total);

    return;
}

এটি পুরোপুরি বৈধ C99 কোড। যদিও এটির একটি অসুবিধা রয়েছে - আপনি SUM()প্যারাম ছাড়াই ম্যাক্রো চালাতে পারবেন না , তবে জিসিসির এর সমাধান রয়েছে - এখানে দেখুন

সুতরাং জিসিসির ক্ষেত্রে আপনাকে এই জাতীয় ম্যাক্রো সংজ্ঞায়িত করতে হবে:

#define       NUMARGS(...)  (sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1)
#define       SUM(...)  sum(NUMARGS(__VA_ARGS__), ##__VA_ARGS__)

এবং এটি খালি প্যারামিটার তালিকার সাথেও কাজ করবে


4
ওম, এটি ওপিতে কাজ করবে না, তার BOOST_PP এর আকার দরকার যা সংকলনের সময় চলে।
কর্নেল কিসিলেউইচজ

4
চালাক! এটাও কি কখন কাজ করে sizeof(int) != sizeof(void *)?
অ্যাডাম লিস

4
@ কর্নেল যেকোন ম্যাক্রোর মতো এটি সংকলন সময়ে মূল্যায়ন করা হয়। বুস্ট সম্পর্কে আমার ধারণা নেই, তবে যাইহোক বুস্টের দরকার নেই।
qrdl

4
@Adam কারণ আমি নিক্ষেপ {__VA_ARGS__}করার int[], এটা ঠিক নয় int[]প্রকৃত বিষয়বস্তু নির্বিশেষে__VA_ARGS__
qrdl

4
মার্জিত সমাধান! VS2017 এ কাজ করে। ##একটি খালি যেমন VS2017 মধ্যে প্রয়োজন নেই __VA_ARGS__স্বয়ংক্রিয়ভাবে কোনো পূর্ববর্তী কমা মুছে ফেলা হবে।
poby

43

আপনি যদি সি ++ 11 ব্যবহার করেন এবং আপনার সি ++ সংকলন-সময় ধ্রুবক হিসাবে মান প্রয়োজন হয় তবে খুব মার্জিত সমাধান হ'ল:

#include <tuple>

#define MACRO(...) \
    std::cout << "num args: " \
    << std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value \
    << std::endl;

দয়া করে নোট করুন: গণনা সম্পূর্ণরূপে সংকলন সময়ে ঘটে এবং যখনই সংকলন-সময় পূর্ণসংখ্যার প্রয়োজন হয়, উদাহরণস্বরূপ std :: অ্যারেতে একটি টেম্পলেট প্যারামিটার হিসাবে ব্যবহৃত হয়।


4
দুর্দান্ত সমাধান! এবং sizeof((int[]){__VA_ARGS__})/sizeof(int)উপরোক্ত পরামর্শের বিপরীতে , এটি কাজ করে এমনকি যখন তর্কগুলি সকলের কাছে দেওয়া যায় না int
উইম

রাজি। দুর্দান্ত সমাধান! ++।
ডেভনেটর

টেমপ্লেটগুলি, যেমন NUMARGS (যোগফল <1,2>) দিয়ে কাজ করে না; Godbolt.org/z/_AAxmL

4
আমি ... মনে করি এটি সম্ভবত @Jorgbrown এর পক্ষে এটি একটি পয়েন্ট হতে পারে, কমপক্ষে বেশিরভাগ ক্ষেত্রে যেখানে এটি উঠে আসে। যেহেতু এটি গণনা করার জন্য প্রিপ্রসেসরের পরিবর্তে সংকলকটির উপর নির্ভর করে, তাই এটি সংকলকটি দেখেছে এমন যুক্তিগুলির সংখ্যা দেয় যা সম্ভবত বেশিরভাগ প্রোগ্রামারদের প্রত্যাশার সাথে মিলবে। এটা তোলে করবে যদিও কষ্ট কারণ যদি আপনি এটি একাউন্টে প্রাক প্রসেসর লালসা নিতে আশা।
জাস্টিন সময় - মনিকা পুনরায়

চমত্কার উত্তর। আপনি এটিকে ম্যাক্রোতে রাখতে পারেন#define NUM_ARGS(...) std::tuple_size<decltype(std::make_tuple(__VA_ARGS__))>::value
রিচার্ড হোয়াইটহেড

23

সুবিধার জন্য, এখানে একটি বাস্তবায়ন যা 0 থেকে 70 টি আর্গুমেন্টের জন্য কাজ করে এবং ভিজ্যুয়াল স্টুডিও, জিসিসি এবং ক্ল্যাংয়ে কাজ করে । আমি বিশ্বাস করি এটি ভিজ্যুয়াল স্টুডিও 2010 এবং তার পরে কাজ করবে তবে এটি কেবল ভিএস ২০১৩ এ পরীক্ষা করেছে।

#ifdef _MSC_VER // Microsoft compilers

#   define GET_ARG_COUNT(...)  INTERNAL_EXPAND_ARGS_PRIVATE(INTERNAL_ARGS_AUGMENTER(__VA_ARGS__))

#   define INTERNAL_ARGS_AUGMENTER(...) unused, __VA_ARGS__
#   define INTERNAL_EXPAND(x) x
#   define INTERNAL_EXPAND_ARGS_PRIVATE(...) INTERNAL_EXPAND(INTERNAL_GET_ARG_COUNT_PRIVATE(__VA_ARGS__, 69, 68, 67, 66, 65, 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 INTERNAL_GET_ARG_COUNT_PRIVATE(_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, _64, _65, _66, _67, _68, _69, _70, count, ...) count

#else // Non-Microsoft compilers

#   define GET_ARG_COUNT(...) INTERNAL_GET_ARG_COUNT_PRIVATE(0, ## __VA_ARGS__, 70, 69, 68, 67, 66, 65, 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 INTERNAL_GET_ARG_COUNT_PRIVATE(_0, _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, _64, _65, _66, _67, _68, _69, _70, count, ...) count

#endif

static_assert(GET_ARG_COUNT() == 0, "GET_ARG_COUNT() failed for 0 arguments");
static_assert(GET_ARG_COUNT(1) == 1, "GET_ARG_COUNT() failed for 1 argument");
static_assert(GET_ARG_COUNT(1,2) == 2, "GET_ARG_COUNT() failed for 2 arguments");
static_assert(GET_ARG_COUNT(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, 64, 65, 66, 67, 68, 69, 70) == 70, "GET_ARG_COUNT() failed for 70 arguments");

মাইক্রোসফ্ট রূপটি আইএমএইচও শূন্য আর্গুমেন্টে ব্যর্থ।
ভোরফোনডেল

মাইক্রোসফ্ট রূপটি শূন্য আর্গুমেন্টের জন্য ওয়ার্লফন্ডেল কাজ করে। উপরে উদাহরণস্বরূপ প্রথম স্থির_সেসਟਰটি শূন্য-আর্গুমেন্টের ক্ষেত্রে একটি নির্দিষ্ট পরীক্ষা এবং আমি কেবল এটি ভিজ্যুয়াল স্টুডিও 2017 v15.8.9 এ সংকলন করে চালিয়েছি।
ক্রিস ক্লাইন

আকর্ষণীয় - মাইক্রোসফ্ট নন-মাইক্রোসফ্ট সংকলকটিতে মাইক্রোসফ্ট রূপটি ব্যবহার করা কার্যকর হয় না - আপনি কি জানেন যে এম $ প্রিপ্রসেসরটি ভিন্নভাবে কী করে কোডটি বিপরীত উপায়ে কাজ করে? বিটিডাব্লু আমি সি চেষ্টা করেছি, সি ++ নয়;
ভোরফন্ডেল

আমি বিশ্বাস করি কারণ এমএসভিসি "শূন্য দৈর্ঘ্য __VA_ARGS__" (যা সি ++ এর মধ্যে প্রযুক্তিগতভাবে একটি (নিকট-সর্বজনীন, ডি ফ্যাক্টো স্ট্যান্ডার্ড) সি ++ ২০ অবধি সংকলক এক্সটেনশন) সম্পর্কে কিছুটা নিখুঁত is সর্বাধিক (? সব) কম্পাইলার শূন্য দৈর্ঘ্যের দিই, কিন্তু শেষে কমা উপর শ্বাসরোধ যদি তালিকা করা হয় খালি (এবং জমিদার ##একটি proto- যেমন __VA_OPT__এই ক্ষেত্রে কমা মুছে ফেলার জন্য); এক্সটেনশানের MSVC এর সংস্করণ মাত্র কমা উপর শ্বাসরোধ করে না (কিন্তু হবে ওভারলোড উপর শ্বাসরোধ ##)। এমএসভিসির তুলনা unused, __VA_ARGS__নন-এমএসভিসি 0, ## __VA_ARGS__; উভয়ই সঠিক নয়, সমস্যাটি হ'ল তারা আলাদা different
জাস্টিন সময় - মনিকা পুনরায়

@ ভার্মফন্ডেল, যদিও সি-তে এটি একই ছিল কিনা তা আমি নিশ্চিত নই, যেহেতু আমি আমার বুকমার্কটি সর্বশেষতম খসড়াটিতে হারিয়ে ফেলেছি।
জাস্টিন সময় - মনিকা পুনরায়

11

সংকলন-সময় আর্গুমেন্টগুলির সংখ্যা সন্ধানের জন্য কয়েকটি সি ++ 11 সমাধান রয়েছে তবে আমি অবাক হয়ে দেখেছি যে এত সহজ কিছু আর কেউ প্রস্তাব করেনি:

#define VA_COUNT(...) detail::va_count(__VA_ARGS__)

namespace detail
{
    template<typename ...Args>
    constexpr std::size_t va_count(Args&&...) { return sizeof...(Args); }
}

এটির মধ্যেও <tuple>শিরোনাম অন্তর্ভুক্তির প্রয়োজন নেই ।


4
"তবে কেন কেবল পরিবর্তিত টেম্পলেট এবং আকারের ব্যবহার করবেন না ... পরিবর্তে (আমার নিজের উত্তর হিসাবে)" সি ++ একটি দানব হয়ে গেছে। এর অনেকগুলি বৈশিষ্ট্য রয়েছে এবং এগুলির মধ্যে অনেকগুলি যেমন ভের্যাডিক টেম্পলেটগুলি খুব কম ব্যবহৃত হয়। আপনি এটি সম্পর্কে পড়া, আপনি কিছু উদাহরণ লিখুন এবং তারপর আপনি এটি ভুলে যান। সুতরাং, সঠিক সময়ে সঠিক ধারণাটি নিয়ে আসা শক্ত। যেহেতু আপনার সমাধানটি আমার চেয়ে ভাল বিকল্প বলে মনে হচ্ছে, তাই আমি প্রাকৃতিক নির্বাচনকে কাজ করতে দেব এবং আমি আমার সমাধানটি মুছব।
zdf

4
@ জেডডিএফ বোধগম্য, তবে আমি ক্রমাগতভাবে ভেরিয়েডিক টেম্পলেট ব্যবহার করতে পারি। আমার প্রোগ্রামগুলি সি ++ 11 সাল থেকে অনেক বেশি শক্তিশালী হয়ে উঠেছে এবং এর অন্যতম প্রধান কারণ এটি one আপনার উত্তরটি মুছে ফেলতে হবে না বলে আমি মনে করি।
monkey0506

4
এটি স্মেথ লাইক দিয়ে কাজ করবে না VA_COUNT(&,^,%)। এছাড়াও, আপনি যদি কোনও মজাদার মাধ্যমে গণনা করছেন তবে ম্যাক্রো তৈরিতে আমি কোনও দর্শন দেখতে পাচ্ছি না।
কিওয়ারটি

এই সমাধানটি এখনও একটি প্রশ্ন হিসাবে রয়ে গেছে: VA_COUNT এর প্যারামিটারগুলি সমস্ত সনাক্তকারী যা এখনও কোনও ভেরিয়েবল বা কিছু হিসাবে সংজ্ঞায়িত হয়নি এবং এর ফলে ত্রুটির কারণ হয়ে যায় '*** ভেরিয়েবল সংজ্ঞায়িত হয়নি'। এই সমাধানের জন্য কোনো উপায় আছে কি?
আইপিড

8

এটি gcc / llvm এর সাথে 0 টি আর্গুমেন্টের সাথে কাজ করে। [লিঙ্কগুলি বোবা হয়]

/*
 * we need a comma at the start for ##_VA_ARGS__ to consume then
 * the arguments are pushed out in such a way that 'cnt' ends up with
 * the right count.  
 */
#define COUNT_ARGS(...) COUNT_ARGS_(,##__VA_ARGS__,6,5,4,3,2,1,0)
#define COUNT_ARGS_(z,a,b,c,d,e,f,cnt,...) cnt

#define C_ASSERT(test) \
    switch(0) {\
      case 0:\
      case test:;\
    }

int main() {
   C_ASSERT(0 ==  COUNT_ARGS());
   C_ASSERT(1 ==  COUNT_ARGS(a));
   C_ASSERT(2 ==  COUNT_ARGS(a,b));
   C_ASSERT(3 ==  COUNT_ARGS(a,b,c));
   C_ASSERT(4 ==  COUNT_ARGS(a,b,c,d));
   C_ASSERT(5 ==  COUNT_ARGS(a,b,c,d,e));
   C_ASSERT(6 ==  COUNT_ARGS(a,b,c,d,e,f));
   return 0;
}

ভিজ্যুয়াল স্টুডিও মনে হচ্ছে ## অপারেটরটি খালি যুক্তিটি ব্যবহার করার জন্য ব্যবহৃত হচ্ছে। আপনি সম্ভবত এটির মতো কিছু পেতে পারেন

#define CNT_ COUNT_ARGS
#define PASTE(x,y) PASTE_(x,y)
#define PASTE_(x,y) x ## y
#define CNT(...) PASTE(ARGVS,PASTE(CNT_(__VA_ARGS__),CNT_(1,##__VA_ARGS__)))
//you know its 0 if its 11 or 01
#define ARGVS11 0
#define ARGVS01 0
#define ARGVS12 1
#define ARGVS23 2
#define ARGVS34 3

আমি ভিজ্যুয়াল স্টুডিও ২০০৮-এর জন্য এটি পরীক্ষা করেছি এবং এটি 0 টি আর্গুমেন্টের জন্য কাজ করে নি COUPARGS () = 1.
ব্যবহারকারী 720594

লিঙ্কটি ভাঙ্গা মনে হচ্ছে।
জান স্ম্রিনা

স্থির লিঙ্ক। ভিএস অবশ্যই যথারীতি আলাদা কিছু করছে :)। আমি মনে করি না যে তারা শীঘ্রই যে কোনও সময় পুরোপুরি সি 99 সমর্থন করবে।
ব্যবহারকারী 1187902

4
আর, খালি খালি ##__VA_ARGS__হওয়ার আগে কমা খাওয়া __VA_ARGS__একটি জিসিসি এক্সটেনশন। এটি স্ট্যান্ডার্ড আচরণ নয়।
মনিকা এর মামলা

6

এমএসভিসি এক্সটেনশন সহ:

#define Y_TUPLE_SIZE(...) Y_TUPLE_SIZE_II((Y_TUPLE_SIZE_PREFIX_ ## __VA_ARGS__ ## _Y_TUPLE_SIZE_POSTFIX,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 Y_TUPLE_SIZE_II(__args) Y_TUPLE_SIZE_I __args

#define Y_TUPLE_SIZE_PREFIX__Y_TUPLE_SIZE_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0

#define Y_TUPLE_SIZE_I(__p0,__p1,__p2,__p3,__p4,__p5,__p6,__p7,__p8,__p9,__p10,__p11,__p12,__p13,__p14,__p15,__p16,__p17,__p18,__p19,__p20,__p21,__p22,__p23,__p24,__p25,__p26,__p27,__p28,__p29,__p30,__p31,__n,...) __n

0 - 32 টি আর্গুমেন্টের জন্য কাজ করে। এই সীমাটি সহজেই বাড়ানো যেতে পারে।

সম্পাদনা: সরলীকৃত সংস্করণ (ভিএস2015 14.0.25431.01 আপডেট 3 এবং জিসিসি 7.4.0 এ কাজ করে) অনুলিপি এবং পেস্ট করার জন্য 100 টি আর্গুমেন্ট:

#define COUNTOF(...) _COUNTOF_CAT( _COUNTOF_A, ( 0, ##__VA_ARGS__, 100,\
    99, 98, 97, 96, 95, 94, 93, 92, 91, 90,\
    89, 88, 87, 86, 85, 84, 83, 82, 81, 80,\
    79, 78, 77, 76, 75, 74, 73, 72, 71, 70,\
    69, 68, 67, 66, 65, 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 _COUNTOF_CAT( a, b ) a b
#define _COUNTOF_A( a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,\
    a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,\
    a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,\
    a30, a31, a32, a33, a34, a35, a36, a37, a38, a39,\
    a40, a41, a42, a43, a44, a45, a46, a47, a48, a49,\
    a50, a51, a52, a53, a54, a55, a56, a57, a58, a59,\
    a60, a61, a62, a63, a64, a65, a66, a67, a68, a69,\
    a70, a71, a72, a73, a74, a75, a76, a77, a78, a79,\
    a80, a81, a82, a83, a84, a85, a86, a87, a88, a89,\
    a90, a91, a92, a93, a94, a95, a96, a97, a98, a99,\
    a100, n, ... ) n

4
এটা কি শুধু আমি বা এই ধরনের কোড গন্ধ নিয়ম ভঙ্গ করে ..?
ওসিরিগোথর

এটি আমার পক্ষে কমপক্ষে VS2012 অবধি ভিসি ++, এবং জিসিসি এবং ঝাঁকুনির পাশাপাশি আমার বেসিক পরীক্ষায়ও কাজ করে।
থ্রিবিট

@osirisgothra, ঠিক এর গন্ধ কেন?
ceztko

যদিও এই ম্যাক্রোর বিস্তৃত সংকলক সমর্থন রয়েছে, এটি ম্যাক্রো যুক্তিগুলির সাথে এই জাতীয় স্ট্রিংয়ের মতো কাজ করে না, যেমন Y_TUPLE_SIZE("Hello")এটি একেবারেই অক্ষম করে তোলে। আমি @osirisgothra এর সাথে একমত
ceztko

4
এই ম্যাক্রো আপনার পক্ষে কাজ করতে পারে তবে গুরুতর ত্রুটি রয়েছে। আমি প্রচুর গবেষণা করেছিলাম এবং পরিষ্কার করেছিলাম যে জিসিসি এবং ভিএস-তে কাজ করে er আপনি আমার অনুরূপ প্রশ্নের উত্তরে সেগুলি খুঁজে পেতে পারেন ।
ceztko

3

আমি ধরে নিচ্ছি যে VA_ARGS এর প্রতিটি যুক্তি কমা দ্বারা পৃথক করা হবে। যদি তা হয় তবে আমি মনে করি এটি করার জন্য এটি একটি সুন্দর পরিষ্কার উপায় হিসাবে কাজ করা উচিত।

#include <cstring>

constexpr int CountOccurances(const char* str, char c) {
    return str[0] == char(0) ? 0 : (str[0] == c) + CountOccurances(str+1, c);
}

#define NUMARGS(...) (CountOccurances(#__VA_ARGS__, ',') + 1)

int main(){
    static_assert(NUMARGS(hello, world) == 2, ":(")  ;
    return 0;
}

ঝনঝন 4 এবং জিসিসি 5.1 এর জন্য গডবোল্টে আমার জন্য কাজ করেছেন। এটি সংকলন সময়ে গণনা করবে তবে প্রিপ্রোসেসরটির জন্য মূল্যায়ন করবে না। সুতরাং আপনি যদি FOR_Each বানানোর মতো কিছু করার চেষ্টা করছেন তবে এটি কার্যকর হবে না।


এই উত্তর আন্ডাররেটেড হয়। এটি এমনকি কাজ করবে NUMARGS(hello, world = 2, ohmy42, !@#$%^&*()-+=)!!! প্রতিটি ARG স্ট্রিং কিছু অন্যান্য চিহ্ন মত থাকতে পারে না ','যদিও
pterodragon

পেরেনদের জন্য টুইট করা দরকার, কারণ int count = NUMARGS( foo(1, 2) );1 টির
জর্গাব্রাউন

এটি ল্যাম্বডাস, ফাংশন কল বা প্যারামিটারগুলিতে অতিরিক্ত কমা থাকতে পারে এমন অন্য কোনও কিছুর সাথে প্রত্যাশা অনুযায়ী কাজ করবে না।
নন্দি

এমএসভিসিতে 0 টি
আরগের জন্যও

2

এখানে VA_ARGS এর 0 বা আরও বেশি আর্গুমেন্ট গণনা করার একটি সহজ উপায় সহ , আমার উদাহরণটি সর্বোচ্চ 5 ভেরিয়েবল গ্রহণ করে তবে আপনি চাইলে আপনি আরও যুক্ত করতে পারেন।

#define VA_ARGS_NUM_PRIV(P1, P2, P3, P4, P5, P6, Pn, ...) Pn
#define VA_ARGS_NUM(...) VA_ARGS_NUM_PRIV(-1, ##__VA_ARGS__, 5, 4, 3, 2, 1, 0)


VA_ARGS_NUM()      ==> 0
VA_ARGS_NUM(19)    ==> 1
VA_ARGS_NUM(9, 10) ==> 2
         ...

দুর্ভাগ্যক্রমে VA_ARGS_NUMম্যাক্রোর সাথে ব্যবহার করার সময় #define TESTTESTVA_ARGS_NUM(TEST)#if
পদ্ধতিরটি

@ অ্যান্টনেক আপনি ঠিক কী করেছেন তা পোস্ট করতে পারেন?
এলাহাদি ডিপি ıpɐɥ ן ǝ

0

আপনি টোকেনগুলি স্ট্রিংফাই এবং গণনা করতে পারেন:

int countArgs(char *args)
{
  int result = 0;
  int i = 0;

  while(isspace(args[i])) ++i;
  if(args[i]) ++result;

  while(args[i]) {
    if(args[i]==',') ++result;
    else if(args[i]=='\'') i+=2;
    else if(args[i]=='\"') {
      while(args[i]) {
        if(args[i+1]=='\"' && args[i]!='\\') {
          ++i;
          break;
        }
        ++i;
      }
    }
    ++i;
  }

  return result;
}

#define MACRO(...) \
{ \
  int count = countArgs(#__VA_ARGS__); \
  printf("NUM ARGS: %d\n",count); \
}

4
এই উত্তরের জন্য মুলতুবি থাকা সম্পাদনাটির দিকে একবার নজর রেখেছিলেন - মনে হয় আপনি দুটি অ্যাকাউন্ট পেয়েছেন। আপনি যদি একটির সাথে লেগে থাকেন তবে আপনি নিজের পোস্ট অনুমোদনের জন্য ছাড়াই সম্পাদনা করতে পারবেন।
জে রিচার্ড স্নেপ

0

বুস্ট Preprocessor আসলে যেমন বুস্ট 1.49 হিসাবে এই আছে, BOOST_PP_VARIADIC_SIZE(...)। এটি 64 আকার পর্যন্ত কাজ করে।

ফণা অধীনে, এটি মূলত কর্নেল কিসিলেউইচসের উত্তর হিসাবে একই ।


পছন্দ করেছেন প্রিপ্রসেসরটি সত্যই "শূন্য আর্গুমেন্ট" ধারণাটি ধারণ করে না। আমরা "শূন্য আর্গুমেন্ট" হিসাবে যা মনে করি তা হ'ল প্রিপ্রোসেসর "একটি ফাঁকা যুক্তি"। তবে এটি পূর্ববর্তী কমাটি অপসারণের __VA_OPT__জন্য সি ++ ২০ বা সংকলক এক্সটেনশনগুলি ব্যবহার ##__VA_ARGS__করে স্থিরযোগ্য , যেমন: Godbolt.org/z/X7OvnK
জাস্টিন

0

আমি এখানে উত্তরগুলি অসম্পূর্ণ খুঁজে পেয়েছি।

আমি এখান থেকে সর্বাধিক নিকটতম পোর্টেবল বাস্তবায়নটি পেয়েছি: সি ++ প্রিপ্রোসেসর __VA_ARGS__ আর্গুমেন্টের সংখ্যা

তবে এটি কমপক্ষে ছাড়া জিসিসিতে শূন্য আর্গুমেন্ট নিয়ে কাজ করে না -std=gnu++11 কমান্ড লাইন প্যারামিটার ।

সুতরাং আমি এই সমাধানটিকে এর সাথে একীভূত করার সিদ্ধান্ত নিয়েছি: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/

#define UTILITY_PP_CONCAT_(v1, v2) v1 ## v2
#define UTILITY_PP_CONCAT(v1, v2) UTILITY_PP_CONCAT_(v1, v2)

#define UTILITY_PP_CONCAT5_(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4

#define UTILITY_PP_IDENTITY_(x) x
#define UTILITY_PP_IDENTITY(x) UTILITY_PP_IDENTITY_(x)

#define UTILITY_PP_VA_ARGS_(...) __VA_ARGS__
#define UTILITY_PP_VA_ARGS(...) UTILITY_PP_VA_ARGS_(__VA_ARGS__)

#define UTILITY_PP_IDENTITY_VA_ARGS_(x, ...) x, __VA_ARGS__
#define UTILITY_PP_IDENTITY_VA_ARGS(x, ...) UTILITY_PP_IDENTITY_VA_ARGS_(x, __VA_ARGS__)

#define UTILITY_PP_IIF_0(x, ...) __VA_ARGS__
#define UTILITY_PP_IIF_1(x, ...) x
#define UTILITY_PP_IIF(c) UTILITY_PP_CONCAT_(UTILITY_PP_IIF_, c)

#define UTILITY_PP_HAS_COMMA(...) UTILITY_PP_IDENTITY(UTILITY_PP_VA_ARGS_TAIL(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0))
#define UTILITY_PP_IS_EMPTY_TRIGGER_PARENTHESIS_(...) ,

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

#define UTILITY_PP_IS_EMPTY_(_0, _1, _2, _3) UTILITY_PP_HAS_COMMA(UTILITY_PP_CONCAT5_(UTILITY_PP_IS_EMPTY_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define UTILITY_PP_IS_EMPTY_IS_EMPTY_CASE_0001 ,

#define UTILITY_PP_VA_ARGS_SIZE(...) UTILITY_PP_IIF(UTILITY_PP_IS_EMPTY(__VA_ARGS__))(0, UTILITY_PP_VA_ARGS_SIZE_(__VA_ARGS__, UTILITY_PP_VA_ARGS_SEQ64()))
#define UTILITY_PP_VA_ARGS_SIZE_(...) UTILITY_PP_IDENTITY(UTILITY_PP_VA_ARGS_TAIL(__VA_ARGS__))

#define UTILITY_PP_VA_ARGS_TAIL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14, x, ...) x
#define UTILITY_PP_VA_ARGS_SEQ64() 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0

#define EATER0(...)
#define EATER1(...) ,
#define EATER2(...) (/*empty*/)
#define EATER3(...) (/*empty*/),
#define EATER4(...) EATER1
#define EATER5(...) EATER2
#define MAC0() ()
#define MAC1(x) ()
#define MACV(...) ()
#define MAC2(x,y) whatever

static_assert(UTILITY_PP_VA_ARGS_SIZE() == 0, "1");
static_assert(UTILITY_PP_VA_ARGS_SIZE(/*comment*/) == 0, "2");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a) == 1, "3");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b) == 2, "4");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b, c) == 3, "5");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b, c, d) == 4, "6");
static_assert(UTILITY_PP_VA_ARGS_SIZE(a, b, c, d, e) == 5, "7");
static_assert(UTILITY_PP_VA_ARGS_SIZE((void)) == 1, "8");
static_assert(UTILITY_PP_VA_ARGS_SIZE((void), b, c, d) == 4, "9");
static_assert(UTILITY_PP_VA_ARGS_SIZE(UTILITY_PP_IS_EMPTY_TRIGGER_PARENTHESIS_) == 1, "10");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER0) == 1, "11");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER1) == 1, "12");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER2) == 1, "13");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER3) == 1, "14");
static_assert(UTILITY_PP_VA_ARGS_SIZE(EATER4) == 1, "15");
static_assert(UTILITY_PP_VA_ARGS_SIZE(MAC0) == 1, "16");
// a warning in msvc
static_assert(UTILITY_PP_VA_ARGS_SIZE(MAC1) == 1, "17");
static_assert(UTILITY_PP_VA_ARGS_SIZE(MACV) == 1, "18");
// This one will fail because MAC2 is not called correctly
//static_assert(UTILITY_PP_VA_ARGS_SIZE(MAC2) == 1, "19");

https://godbolt.org/z/3idaKd

  • c++11, msvc 2015, gcc 4.7.1,clang 3.0
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.