সিটিতে ফাংশন ওভারলোডিং কীভাবে অর্জন করবেন?


240

সি তে ফাংশন ওভারলোডিং অর্জনের কোনও উপায় আছে কি? আমি ওভারলোড হওয়া মতো সাধারণ ফাংশনগুলিতে দেখছি

foo (int a)  
foo (char b)  
foo (float c , int d)

আমার মনে হয় কোনও সোজা এগিয়ে যাওয়ার উপায় নেই; আমি যদি উপস্থিত থাকে তবে কাজের সন্ধান করছি।


6
তুমি কেন এটা করতে চাও? সি-তে কোনও পলিমারফিক ক্ষমতা নেই। সুতরাং ফু (র্যান্ডম টাইপ) অসম্ভব। কেবল আসল ফানকস foo_i, foo_ch, foo_d ইত্যাদি তৈরি করুন
jmucchiello

4
আপনি অকার্যকর পয়েন্টার এবং টাইপ আইডি ব্যবহার করে মন্দ পথে যেতে পারেন।
alk

11
আমি মনে করি যে এই প্রশ্নের উত্তরটি মূলত জিজ্ঞাসা করা হয়েছিল যেহেতু নতুন সি স্ট্যান্ডার্ড সহ এটি পরিবর্তিত হয়েছে সেদিকে আমার দৃষ্টি আকর্ষণ করা উচিত ।
লুশেনকো

উত্তর:


127

কয়েকটি সম্ভাবনা রয়েছে:

  1. প্রিন্টফ স্টাইল ফাংশন (আর্গুমেন্ট হিসাবে টাইপ করুন)
  2. ওপেনগাইল শৈলী ফাংশন (ফাংশনের নামে টাইপ করুন)
  3. সি ++ এর সি সাবসেট (আপনি যদি সি ++ সংকলক ব্যবহার করতে পারেন)

1
আপনি ওপেনগাইল স্টাইলের ফাংশনগুলির জন্য লিঙ্কগুলি ব্যাখ্যা বা সরবরাহ করতে পারেন?
এফএল 4 এসএফ

1
@ লেজার: এখানে একটি সাধারণ প্রিন্টফের মতো ফাংশন বাস্তবায়ন।
অ্যালেক্সি ফ্রুঞ্জ

12
নং প্রিন্টফ ওভারলোডিং ফাংশন করে না। এটি ভারার্গ ব্যবহার করে !!! এবং সি ফাংশন ওভারলোডিং সমর্থন করে না।
hqt

52
@hqt উত্তরে কখনই বোঝা শব্দটি বোঝা যায় না।
কিরিয়াস

1
@ ক্রিরিয়াস যদি উত্তর অতিরিক্ত চাপের বিষয়ে না হয় তবে এটি ভুল প্রশ্নে রয়েছে
মাইকেল মরোজেক

233

হ্যাঁ!

যেহেতু এই প্রশ্নটি জিজ্ঞাসা করা হয়েছিল, সেই সময়টিতে স্ট্যান্ডার্ড সি (কোনও এক্সটেনশানগুলি) কার্যকরভাবে ফাংশন ওভারলোডিং (অপারেটর নয়) জন্য সমর্থন পেয়েছে , সি _Generic11 এ কীওয়ার্ড যুক্ত করার জন্য ধন্যবাদ । (৪.৯ সংস্করণ থেকে জিসিসিতে সমর্থিত)

(প্রশ্নটিতে দেখানো ফ্যাশনে ওভারলোডিং সত্যিকার অর্থে "বিল্ট-ইন" নয়, তবে এর মতো কাজ করে এমন কোনও কিছু কার্যকর করা এটি মরিয়া easy

_Genericহিসাবে একই পরিবারের একজন কম্পাইল-টাইম অপারেটর sizeofএবং _Alignof। এটি স্ট্যান্ডার্ড বিভাগ 6.5.1.1 বর্ণিত হয়েছে। এটি দুটি প্রধান প্যারামিটার গ্রহণ করে: একটি অভিব্যক্তি (যা রানটাইমের সময় মূল্যায়ন করা হবে না), এবং একটি টাইপ / এক্সপ্রেশন অ্যাসোসিয়েশন তালিকা যা কিছুটা switchব্লকের মতো দেখায় । _Genericসামগ্রীর মত প্রকাশের সামগ্রিক প্রকার পায় এবং তারপরে তালিকার শেষ ফলাফলের এক্সপ্রেশনটি নির্বাচনের জন্য এটিতে "স্যুইচ" করে:

_Generic(1, float: 2.0,
            char *: "2",
            int: 2,
            default: get_two_object());

উপরের এক্সপ্রেশনটি মূল্যায়ন করে 2- নিয়ন্ত্রণকারী এক্সপ্রেশনটির ধরণ int, সুতরাং এটি intমান হিসাবে যুক্ত অভিব্যক্তিটি চয়ন করে । রানটাইম এ কিছুই রইল না। ( defaultধারাটি isচ্ছিক: আপনি যদি এটি ছেড়ে দেন এবং প্রকারটি মেলে না তবে এটি সংকলনের ত্রুটির কারণ হবে))

ফাংশন ওভারলোডিংয়ের জন্য এটি যেভাবে কার্যকর তা হ'ল এটি সি প্রিপ্রসেসর দ্বারা সন্নিবেশ করা যায় এবং নিয়ন্ত্রণকারী ম্যাক্রোতে প্রেরিত আর্গুমেন্টগুলির ধরণের উপর ভিত্তি করে একটি ফলাফল এক্সপ্রেশন বেছে নিতে পারে। সুতরাং (সি স্ট্যান্ডার্ড থেকে উদাহরণ):

#define cbrt(X) _Generic((X),                \
                         long double: cbrtl, \
                         default: cbrt,      \
                         float: cbrtf        \
                         )(X)

এই ম্যাক্রো একটি ওভারলোডেড cbrtঅপারেশন প্রয়োগ করে, ম্যাক্রোর কাছে আর্গুমেন্টের প্রকারটি প্রেরণ করে, একটি যথাযথ বাস্তবায়ন ফাংশন চয়ন করে এবং তারপরে সেই ফাংশনে আসল ম্যাক্রো যুক্তিটি পাস করে।

সুতরাং আপনার মূল উদাহরণটি বাস্তবায়নের জন্য আমরা এটি করতে পারলাম:

foo_int (int a)  
foo_char (char b)  
foo_float_int (float c , int d)

#define foo(_1, ...) _Generic((_1),                                  \
                              int: foo_int,                          \
                              char: foo_char,                        \
                              float: _Generic((FIRST(__VA_ARGS__,)), \
                                     int: foo_float_int))(_1, __VA_ARGS__)
#define FIRST(A, ...) A

এই ক্ষেত্রে আমরা default:তৃতীয় মামলার জন্য একটি সমিতি ব্যবহার করতে পারতাম , তবে এটি নীতিটি একাধিক যুক্তিতে কীভাবে প্রসারিত করা যায় তা প্রদর্শন করে না। শেষ ফলাফলটি হ'ল আপনি নিজের foo(...)কোডটিতে এর যুক্তিগুলির ধরণ সম্পর্কে চিন্তা না করে (অনেক [1]) ব্যবহার করতে পারেন ।


আরও জটিল অবস্থার জন্য, উদাহরণস্বরূপ বৃহত সংখ্যক তর্কগুলি ওভারলোড করা ফাংশন বা বিভিন্ন সংখ্যার জন্য, আপনি স্বয়ংক্রিয়ভাবে স্ট্যাটিক প্রেরণ কাঠামো উত্পন্ন করতে ইউটিলিটি ম্যাক্রো ব্যবহার করতে পারেন:

void print_ii(int a, int b) { printf("int, int\n"); }
void print_di(double a, int b) { printf("double, int\n"); }
void print_iii(int a, int b, int c) { printf("int, int, int\n"); }
void print_default(void) { printf("unknown arguments\n"); }

#define print(...) OVERLOAD(print, (__VA_ARGS__), \
    (print_ii, (int, int)), \
    (print_di, (double, int)), \
    (print_iii, (int, int, int)) \
)

#define OVERLOAD_ARG_TYPES (int, double)
#define OVERLOAD_FUNCTIONS (print)
#include "activate-overloads.h"

int main(void) {
    print(44, 47);   // prints "int, int"
    print(4.4, 47);  // prints "double, int"
    print(1, 2, 3);  // prints "int, int, int"
    print("");       // prints "unknown arguments"
}

( বাস্তবায়ন এখানে ) তাই কিছু প্রচেষ্টা দিয়ে, আপনি ওভারলোডিংয়ের জন্য স্থানীয় সমর্থন সহ কোনও ভাষার মতো দেখতে বয়লারপ্লেটের পরিমাণ হ্রাস করতে পারেন।

সরাইয়া হিসাবে, C99-তে আর্গুমেন্টের সংখ্যা (ধরণের নয়) ওভারলোড করা ইতিমধ্যে সম্ভব ছিল


[1] নোট করুন যে সি যেভাবে প্রকারের মূল্যায়ন করে তা আপনাকে ত্রিগুণে ছাড়তে পারে। foo_intউদাহরণস্বরূপ, আপনি যদি এটি একটি অক্ষরকে আক্ষরিকভাবে পাস করার চেষ্টা করেন তবে এটি চয়ন করবে এবং আপনি যদি নিজের ওভারলোডগুলি স্ট্রিং আক্ষরিক সমর্থন করতে চান তবে আপনাকে কিছুটা গোলমাল করতে হবে। এখনও সামগ্রিক সুন্দর যদিও।


আপনার উদাহরণের উপর ভিত্তি করে দেখে মনে হচ্ছে কেবলমাত্র অতিরিক্ত জিনিস বোঝাই হচ্ছে ম্যাক্রোর মতো ফাংশন। আমি সঠিকভাবে বুঝতে পেরেছি কিনা তা আমাকে দেখতে দিন: আপনি যদি ফাংশনগুলি ওভারলোড করতে চান তবে আপনি কেবলমাত্র প্রসেস প্রসেসরটি ডানদিকে পাস হওয়া ডেটার ধরণের ভিত্তিতে ফাংশন কলটি ডাইভার্ট করতে ব্যবহার করবেন?
নিক

হায়রে, যখনই সি 11 ধরতে শুরু করে আমি ধরে নিয়েছি মিজরা এই বৈশিষ্ট্যটিকে একই কারণে গ্রহণ করবে না কারণ তারা পরিবর্তনশীল যুক্তি তালিকার তালিকা নিষিদ্ধ করে। আমি আমার বিশ্বের বেশ কাছাকাছি মিশ্র দ্বারা আঁকড়ে থাকার চেষ্টা করি।
নিক

9
@ নিক যে সমস্ত ওভারলোডিং হয়। এটি কেবল অন্য ভাষায় স্পষ্টভাবে পরিচালিত হয়েছে (যেমন আপনি কোনও ভাষায় সত্যই "একটি ওভারলোডড ফাংশনটির একটি পয়েন্টার" পেতে পারেন না, কারণ ওভারলোডিং একাধিক সংস্থাকে বোঝায়)। মনে রাখবেন যে এটি একা প্রিপ্রসেসর দ্বারা করা সম্ভব নয়, এটির জন্য কোনও প্রকারের প্রেরণ প্রয়োজন; প্রিপ্রোসেসর কেবল এটি দেখতে কেমন তা পরিবর্তন করে।
লুশেনকো

1
C99 এর সাথে মোটামুটি পরিচিত এবং এটি কীভাবে করা শিখতে চান এমন কেউ হিসাবে, এটি সি এর জন্যও অত্যধিক জটিল বলে মনে হচ্ছে
টাইলার ক্রম্পটন

5
@ টাইলারক্রম্পটন এটি সংকলন সময়ে মূল্যায়ন করা হয়।
জ্যাব

75

যেমন ইতিমধ্যে বলা হয়েছে, ওভারলোডিং এই অর্থে যে আপনি বোঝাতে চাইছেন সি দ্বারা সমর্থিত নয় সমস্যাটি সমাধান করার জন্য একটি সাধারণ বুদ্ধি হ'ল ফাংশনটিকে একটি ট্যাগ ইউনিয়ন গ্রহণ করতে বাধ্য করা । এটি একটি structপ্যারামিটার দ্বারা প্রয়োগ করা হয় , যেখানে structনিজেই কিছু ধরণের সূচক থাকে যেমন একটি enumএবং unionবিভিন্ন ধরণের মান values উদাহরণ:

#include <stdio.h>

typedef enum {
    T_INT,
    T_FLOAT,
    T_CHAR,
} my_type;

typedef struct {
    my_type type;
    union {
        int a; 
        float b; 
        char c;
    } my_union;
} my_struct;

void set_overload (my_struct *whatever) 
{
    switch (whatever->type) 
    {
        case T_INT:
            whatever->my_union.a = 1;
            break;
        case T_FLOAT:
            whatever->my_union.b = 2.0;
            break;
        case T_CHAR:
            whatever->my_union.c = '3';
    }
}

void printf_overload (my_struct *whatever) {
    switch (whatever->type) 
    {
        case T_INT:
            printf("%d\n", whatever->my_union.a);
            break;
        case T_FLOAT:
            printf("%f\n", whatever->my_union.b);
            break;
        case T_CHAR:
            printf("%c\n", whatever->my_union.c);
            break;
    }

}

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

    s.type=T_INT;
    set_overload(&s);
    printf_overload(&s);

    s.type=T_FLOAT;
    set_overload(&s);
    printf_overload(&s);

    s.type=T_CHAR;
    set_overload(&s);
    printf_overload(&s); 
}

22
কেন তুমি সব করতে হতো না whateverগুলি পৃথক ফাংশন মধ্যে ( set_int, set_floatইত্যাদি)। তারপরে "টাইপের সাথে ট্যাগিং" হয়ে যায় "ফাংশনের নামের সাথে টাইপের নাম যুক্ত করুন"। এই উত্তরের সংস্করণটিতে আরও টাইপিং, আরও রানটাইম ব্যয়, সংকলনের সময় ধরা পড়বে না এমন আরও ত্রুটির সম্ভাবনা রয়েছে ... আমি এইভাবে জিনিসগুলি করার কোনও সুবিধা দেখতে ব্যর্থ হই ! ১ up টি আপভোটস ?!
বেন

20
বেন, এই উত্তরটি upvated কারণ এটি প্রশ্নের উত্তর দেয়, কেবল "" এটি করবেন না "বলার পরিবর্তে। আপনি সঠিক যে পৃথক ফাংশন ব্যবহার করা সিতে আরও বুদ্ধিমানের কাজ, তবে কেউ যদি সিতে পলিমারফিজম চান, এটি করার এটি একটি ভাল উপায়। আরও, এই উত্তরটি দেখায় যে আপনি কীভাবে একটি সংকলক বা ভিএম-তে রান-টাইম পলিমারফিজম প্রয়োগ করবেন: কোনও ধরণের সাথে মান ট্যাগ করুন এবং তারপরে প্রেরণ করুন। এটি মূল প্রশ্নের উত্তরের উত্তর।
নিলস ভন বার্থ

20

এখানে সিটিতে সবচেয়ে স্পষ্ট ও সংক্ষিপ্ত উদাহরণটি দেখলাম যে ফাংশন ওভারলোডিং প্রদর্শিত হচ্ছে:

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

int addi(int a, int b) {
    return a + b;
}

char *adds(char *a, char *b) {
    char *res = malloc(strlen(a) + strlen(b) + 1);
    strcpy(res, a);
    strcat(res, b);
    return res;
}

#define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)

int main(void) {
    int a = 1, b = 2;
    printf("%d\n", add(a, b)); // 3

    char *c = "hello ", *d = "world";
    printf("%s\n", add(c, d)); // hello world

    return 0;
}

https://gist.github.com/barosl/e0af4a92b2b8cabd05a7


1
আমি মনে করি এটি আত্মাক্রমে স্ট্যাকওভারফ্লো. com/ a/25026358/ 1240268 এর এক ধাপ (তবে কম ব্যাখ্যা দিয়ে)।
অ্যান্ডি হেডেন

1
আমি অবশ্যই 1212268 # স্লাইসিং এবং ডাইটিং চপটিতে সম্পূর্ণ এবং চলমানযোগ্য কোডের 1 টি একটানা ক্রমাগত ব্লকটিকে পছন্দ করি। প্রতিটি তাদের নিজস্ব।
জে টেলর

1
আমি উত্তরগুলি পছন্দ করি যা তারা কী করছে এবং কেন তারা কাজ করে তা ব্যাখ্যা করে। এটি না। "সেরা আমি এখনও দেখেছি:" প্রকাশ করা হয় না।
আন্ডারস্কোর_ডে

19

যদি আপনার সংকলকটি জিসিসি হয় এবং প্রতিবার নতুন ওভারলোড যুক্ত করার সময় আপনি হাতের আপডেটগুলি করতে কিছু মনে করেন না তবে আপনি কিছু ম্যাক্রো ম্যাজিক করতে পারেন এবং কলারদের ক্ষেত্রে আপনি যে ফলাফলটি চান তা পেতে পারেন, তবে এটি লিখতে তেমন সুন্দর নয় ... তবে এটি সম্ভব

__builtin_types_comp موافق_p দেখুন, তারপরে ম্যাক্রো সংজ্ঞায়িত করতে এটি ব্যবহার করুন যা এর মতো কিছু করে

#define foo(a) \
((__builtin_types_compatible_p(int, a)?foo(a):(__builtin_types_compatible_p(float, a)?foo(a):)

তবে হ্যাঁ দুষ্টু, ঠিক না

সম্পাদনা: C1X এ জাতীয় চেহারাটির মতো জেনেরিক এক্সপ্রেশনগুলির জন্য সমর্থন পাবে:

#define cbrt(X) _Generic((X), long double: cbrtl, \
                              default: cbrt, \
                              float: cbrtf)(X)

13

হ্যাঁ, সাজান।

এখানে আপনি উদাহরণস্বরূপ যান:

void printA(int a){
printf("Hello world from printA : %d\n",a);
}

void printB(const char *buff){
printf("Hello world from printB : %s\n",buff);
}

#define Max_ITEMS() 6, 5, 4, 3, 2, 1, 0 
#define __VA_ARG_N(_1, _2, _3, _4, _5, _6, N, ...) N
#define _Num_ARGS_(...) __VA_ARG_N(__VA_ARGS__) 
#define NUM_ARGS(...) (_Num_ARGS_(_0, ## __VA_ARGS__, Max_ITEMS()) - 1) 
#define CHECK_ARGS_MAX_LIMIT(t) if(NUM_ARGS(args)>t)
#define CHECK_ARGS_MIN_LIMIT(t) if(NUM_ARGS(args) 
#define print(x , args ...) \
CHECK_ARGS_MIN_LIMIT(1) printf("error");fflush(stdout); \
CHECK_ARGS_MAX_LIMIT(4) printf("error");fflush(stdout); \
({ \
if (__builtin_types_compatible_p (typeof (x), int)) \
printA(x, ##args); \
else \
printB (x,##args); \
})

int main(int argc, char** argv) {
    int a=0;
    print(a);
    print("hello");
    return (EXIT_SUCCESS);
}

এটি 0 এবং হ্যালো আউটপুট দেবে .. প্রিন্টএ এবং প্রিন্টবি থেকে।


2
int main (int argc, char ** argv) {int a = 0; প্রিন্ট (ক); মুদ্রণ ( "হ্যালো"); রিটার্ন (EXIT_SUCCESS); 0 0 এবং হ্যালো আউটপুট দেবে .. প্রিন্টএ এবং প্রিন্টবি থেকে ...
ক্যাপ্টেন বারবোসা

1
__ বিল্টিন_ টাইপ_সামগ্রী_পি, এটি কি জিসিসি সংকলক নির্দিষ্ট নয়?
সোগারটার

11

নিম্নলিখিত পদ্ধতিরটি a2800276 এর মতো, তবে কিছু সি 99 ম্যাক্রো যাদু যুক্ত রয়েছে:

// we need `size_t`
#include <stddef.h>

// argument types to accept
enum sum_arg_types { SUM_LONG, SUM_ULONG, SUM_DOUBLE };

// a structure to hold an argument
struct sum_arg
{
    enum sum_arg_types type;
    union
    {
        long as_long;
        unsigned long as_ulong;
        double as_double;
    } value;
};

// determine an array's size
#define count(ARRAY) ((sizeof (ARRAY))/(sizeof *(ARRAY)))

// this is how our function will be called
#define sum(...) _sum(count(sum_args(__VA_ARGS__)), sum_args(__VA_ARGS__))

// create an array of `struct sum_arg`
#define sum_args(...) ((struct sum_arg []){ __VA_ARGS__ })

// create initializers for the arguments
#define sum_long(VALUE) { SUM_LONG, { .as_long = (VALUE) } }
#define sum_ulong(VALUE) { SUM_ULONG, { .as_ulong = (VALUE) } }
#define sum_double(VALUE) { SUM_DOUBLE, { .as_double = (VALUE) } }

// our polymorphic function
long double _sum(size_t count, struct sum_arg * args)
{
    long double value = 0;

    for(size_t i = 0; i < count; ++i)
    {
        switch(args[i].type)
        {
            case SUM_LONG:
            value += args[i].value.as_long;
            break;

            case SUM_ULONG:
            value += args[i].value.as_ulong;
            break;

            case SUM_DOUBLE:
            value += args[i].value.as_double;
            break;
        }
    }

    return value;
}

// let's see if it works

#include <stdio.h>

int main()
{
    unsigned long foo = -1;
    long double value = sum(sum_long(42), sum_ulong(foo), sum_double(1e10));
    printf("%Le\n", value);
    return 0;
}

11

এটি কিছুটা সাহায্য নাও করতে পারে তবে আপনি ঝাঁকুনি ব্যবহার করলে আপনি ওভারলোডযোগ্য বৈশিষ্ট্যটি ব্যবহার করতে পারেন - সি হিসাবে সংকলন করার পরেও এটি কাজ করে

http://clang.llvm.org/docs/AttributeReference.html#overloadable

শিরোলেখ

extern void DecodeImageNow(CGImageRef image, CGContextRef usingContext) __attribute__((overloadable));
extern void DecodeImageNow(CGImageRef image) __attribute__((overloadable));

বাস্তবায়ন

void __attribute__((overloadable)) DecodeImageNow(CGImageRef image, CGContextRef usingContext { ... }
void __attribute__((overloadable)) DecodeImageNow(CGImageRef image) { ... }

10

যে অর্থে আপনি বোঝাতে চেয়েছেন - না, আপনি পারবেন না।

আপনি va_argযেমন একটি ফাংশন ঘোষণা করতে পারেন

void my_func(char* format, ...);

, তবে আপনাকে প্রথম আর্গুমেন্টে - যেমনটি printf()করে ভেরিয়েবলের সংখ্যা এবং তাদের প্রকারের সম্পর্কে কিছু ধরণের তথ্য পাস করতে হবে ।


6

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

ম্যাক্রো দিয়ে সাধারণ জেনেরিক অপারেশন করা যেতে পারে:

#define max(x,y) ((x)>(y)?(x):(y))

যদি আপনার সংকলক টাইফফ সমর্থন করে তবে আরও জটিল ক্রিয়াকলাপ ম্যাক্রোতে রাখা যেতে পারে। তারপরে একই অপারেশনকে বিভিন্ন ধরণের সমর্থন করার জন্য আপনার কাছে প্রতীক foo (x) থাকতে পারে, তবে আপনি বিভিন্ন ওভারলোডের মধ্যে আচরণ পরিবর্তন করতে পারবেন না। আপনি যদি ম্যাক্রোগুলের পরিবর্তে প্রকৃত ফাংশন চান তবে আপনি নামটি টাইপ করতে এবং এটি অ্যাক্সেস করার জন্য দ্বিতীয় পেষ্টিং ব্যবহার করতে সক্ষম হতে পারেন (আমি চেষ্টা করি নি)।


আপনি ম্যাক্রো ভিত্তিক পদ্ধতির উপর আরও কিছু ব্যাখ্যা করতে পারেন।
এফএল 4 এসএফ

4

Leushenko এর উত্তর সত্যিই শীতল হয় - কেবলমাত্র: fooউদাহরণস্বরূপ জিসিসি, এই স্থিতিতে ব্যর্থ সঙ্গে কম্পাইল না foo(7), ওভার হুমড়ি FIRSTম্যাক্রো এবং প্রকৃত ফাংশন কল ( (_1, __VA_ARGS__)একটি উদ্বৃত্ত কমা দিয়ে অবশিষ্ট উপরন্তু, আমরা বিপদে যদি আমরা অতিরিক্ত overloads প্রদান করতে চান। যেমন 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 প্রদান করে returns তালিকাটি খালি থাকায় বা না থাকায় __VA_ARGS__ শর্তাধীন আমরা কমা রেখে দিলে আমরা এই সমস্যাটি "সহজেই" দূর করতে পারি:

#define NARG(...) ARG4_(__VA_ARGS__ COMMA(__VA_ARGS__) 4, 3, 2, 1, 0)

যে লাগছিল সহজ, কিন্তু COMMAম্যাক্রো বেশ ভারী এক; ভাগ্যক্রমে, বিষয়টি ইতিমধ্যে জেনস গুস্ট্টের একটি ব্লগে coveredাকা হয়েছে (ধন্যবাদ, জেনস)। মূল কৌশলটি হ'ল ফাংশন ম্যাক্রোগুলি প্রসারণ করা হয় না তবে বন্ধনীর অনুসরণ না করা হয়, আরও ব্যাখ্যার জন্য জেনসের ব্লগটি দেখুন ... আমাদের কেবল আমাদের প্রয়োজনের জন্য ম্যাক্রোগুলিকে কিছুটা পরিবর্তন করতে হবে (আমি সংক্ষিপ্ত নাম ব্যবহার করতে যাচ্ছি) এবং ব্রেভিটির জন্য কম যুক্তি)।

#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;
}

1

আপনি কি কেবল সি ++ ব্যবহার করতে পারবেন না এবং এটি বাদে অন্য সমস্ত সি ++ বৈশিষ্ট্য ব্যবহার করতে পারবেন না?

যদি এখনও ঠিক কঠোর সি না হয় তবে আমি পরিবর্তে বৈকল্পিক ফাংশনগুলির পরামর্শ দেব ।


3
যদি ওএস কোডিং করছে তার জন্য যদি কোনও সি ++ সংকলক উপলব্ধ না হয়।
ব্রায়ান

2
শুধু তা-ই নয় তবে তিনি এমন একটি সি এবিআইও চাইবেন যার মধ্যে নাম জড়িত না।
স্পুড 86

-3

এই ক্রিয়াকলাপগুলি extern "C++"এমনভাবে ঘোষণা করার চেষ্টা করুন যেন আপনার সংকলক এটি সমর্থন করে, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspx


3
এটি নাম ম্যাঙ্গেলিংয়ে তাদের অনন্য নাম দেওয়ার জন্য পরিবর্তন করতে পারে (সম্ভবত না) তবে এটি হঠাৎ সি ওভারলোড রেজোলিউশন নিয়ম দেয় না।
বেন ভয়েগট

-4

আমি আশা করি নীচের কোডটি আপনাকে ফাংশন ওভারলোডিং বুঝতে সহায়তা করবে

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

int fun(int a, ...);
int main(int argc, char *argv[]){
   fun(1,10);
   fun(2,"cquestionbank");
   return 0;
}
int fun(int a, ...){
  va_list vl;
  va_start(vl,a);

  if(a==1)
      printf("%d",va_arg(vl,int));
   else
      printf("\n%s",va_arg(vl,char *));
}

2
একটি উত্তরের ব্যাখ্যা করা উচিত যে এটি কী করছে এবং এটি কেন কাজ করে। যদি তা না হয় তবে এটি কীভাবে কাউকে কিছু বুঝতে সহায়তা করতে পারে?
আন্ডারস্কোর_ডে

এখানে কোনও ওভারলোডিং নেই।
মেলপোমেন

va_end কখনই কল করা হয়নি
ব্যবহারকারী 2262111
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.