সি / সি ++ ম্যাক্রোতে কমা


103

বলুন আমাদের কাছে এই জাতীয় ম্যাক্রো রয়েছে

#define FOO(type,name) type name

যা আমরা ব্যবহার করতে পারে

FOO(int, int_var);

তবে সর্বদা এটির মতো সহজ নয়:

FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2

অবশ্যই আমরা করতে পারি:

 typedef std::map<int, int> map_int_int_t;
 FOO(map_int_int_t, map_var); // OK

যা খুব আর্গমনিক নয়। প্লাস ধরনের অসম্পূর্ণতা মোকাবেলা করতে হবে। ম্যাক্রো দিয়ে এটি সমাধান করার কোনও ধারণা?


আমি অনুমান করছি অক্ষরগুলিকে আক্ষরিক করে তোলার জন্য আপনাকে একটি অর্থ সহ পালাতে হবে।
জয়ট

কমপক্ষে সি ++ এ আপনি যে কোনও জায়গায় টাইপডেফ রাখতে পারেন, তাই আপনি কেন এটি "আগে থেকেই" থাকতে হবে তা নিশ্চিত নই।
ভন ক্যাটো

উত্তর:


108

কারণ কোণ বন্ধনী এছাড়াও প্রতিনিধিত্ব (অথবা ঘটতে) করতে পারেন তুলনা অপারেটরদের <, >, <=এবং >=, ম্যাক্রো সম্প্রসারণ কোণ বন্ধনী ভিতরে কমা উপেক্ষা করতে পারেন না মত প্রথম বন্ধনী মধ্যে আছে। (এটি বর্গক্ষেত্র বন্ধনী এবং ধনুর্বন্ধনীগুলির জন্যও সমস্যা, যদিও এটি সাধারণত ভারসাম্যযুক্ত জোড় হিসাবে দেখা দেয়)) আপনি ম্যাক্রো যুক্তিটি বন্ধনীতে বন্ধ করতে পারেন:

FOO((std::map<int, int>), map_var);

এর পরে সমস্যাটি হ'ল প্যারামিটারটি ম্যাক্রো প্রসারণের অভ্যন্তরে প্রথম বন্ধনীরূপে থেকে যায় যা এটি বেশিরভাগ প্রসঙ্গে একটি প্রকার হিসাবে পড়তে বাধা দেয়।

এটি কার্যকর করার জন্য একটি দুর্দান্ত কৌশলটি হ'ল সি ++ তে আপনি কোনও ফাংশনের প্রকারটি ব্যবহার করে একটি প্রথম বন্ধনযুক্ত টাইপের নাম থেকে টাইপনেমটি বের করতে পারেন:

template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
FOO((std::map<int, int>), map_var);

ফাংশন ধরণের গঠনের ফলে অতিরিক্ত বন্ধনী অগ্রাহ্য করা হওয়ায় আপনি এই ম্যাক্রোটি বন্ধনীর সাথে বা ছাড়াই ব্যবহার করতে পারেন যেখানে টাইপের নামটিতে কমা অন্তর্ভুক্ত নয়:

FOO((int), int_var);
FOO(int, int_var2);

সিতে অবশ্যই এটি প্রয়োজনীয় নয় কারণ প্রকারের নামের মধ্যে প্রথম বন্ধনীর বাইরে কমা থাকতে পারে না। সুতরাং, ক্রস-ল্যাঙ্গুয়েজ ম্যাক্রোর জন্য আপনি লিখতে পারেন:

#ifdef __cplusplus__
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
#else
#define FOO(t,name) t name
#endif

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

@ উইলিয়ামকাস্টোড যেমন আমার স্মরণ আছে, আমি খুব বিরক্তিকর পার্স সমস্যা সম্পর্কিত রেফারেন্স সহ ফাংশনের ধরণ এবং ফাংশন ঘোষণার ব্যাকরণ অধ্যয়ন করছিলাম, সুতরাং আমি সচেতন ছিলাম যে অপ্রয়োজনীয় বন্ধনীগুলি সেই প্রসঙ্গে কোনও প্রকারের ক্ষেত্রে প্রয়োগ করা যেতে পারে।
ইকামত্মর

টেম্পলেটগুলির সাথে কাজ করার সময় আমি এই পদ্ধতিতে একটি সমস্যা পেয়েছি। যাক আমি যে কোডটি চেয়েছিলাম তা হ'ল: template<class KeyType, class ValueType> void SomeFunc(FOO(std::map<KeyType, ValueType>) element) {}আমি যদি এখানে এই সমাধানটি প্রয়োগ করি তবে ম্যাক্রোর পিছনের স্ট্রাকগুলি নির্ভরশীল প্রকারে পরিণত হয় এবং টাইপের নামটির উপসর্গটি এখন টাইপটিতে প্রয়োজনীয়। আপনি এটি যুক্ত করতে পারেন, তবে টাইপ ছাড়ের বিয়োগ হয়েছে, সুতরাং আপনাকে এখন ফাংশনটি কল করতে টাইপ আর্গুমেন্টকে ম্যানুয়ালি তালিকাবদ্ধ করতে হবে। আমি কমাটির জন্য ম্যাক্রো সংজ্ঞায়নের মন্দিরের পদ্ধতিটি ব্যবহার করে শেষ করেছি। এটি দেখতে সুন্দর দেখাচ্ছে না, তবে এটি পুরোপুরি কার্যকর হয়েছে।
রজার স্যান্ডার্স

উত্তরের একটি ছোট সমস্যা: এটিতে বলা হয়েছে যে কমাগুলি ভিতরে উপেক্ষা করা হয় [] এবং {}তারা তা নয়, এটি কেবল ()দুঃখের সাথে কাজ করে । দেখুন: তবে স্কোয়ার বন্ধনী বা ব্রেসগুলির ভারসাম্য বজায় রাখার কোনও প্রয়োজন নেই ...
ব্রেসগুলি

দুর্ভাগ্যক্রমে এটি এমএসভিসিতে কাজ করে না: Godbolt.org/z/WPjYW8 । দেখে মনে হচ্ছে এমএসভিসি একাধিক প্যারেন যোগ করার অনুমতি দেয় না এবং এটি পার্স করতে ব্যর্থ হয়। একটি সমাধান যা মার্জিত নয় তবে দ্রুত (কম টেম্পলেট ইনস্ট্যান্টেশন) নয় কমা-এডি যুক্তিটিকে একটি মোড়কের ম্যাক্রোতে মোড়ানো #define PROTECT(...) argument_type<void(__VA_ARGS__)>::type। একাধিক ম্যাক্রোগুলির মাধ্যমেও যুক্তিগুলি এখন সহজেই সম্ভব এবং সহজ ধরণের জন্য আপনি সুরক্ষা বাদ দিতে পারেন। তবে ফাংশনের
ধরণগুলি এরূপ

119

যদি আপনি বন্ধনী ব্যবহার করতে না পারেন এবং আপনি মাইকের SINGLE_ARG সমাধানটি পছন্দ করেন না, কেবল একটি COMMA সংজ্ঞা দিন:

#define COMMA ,

FOO(std::map<int COMMA int>, map_var);

এটি যেমন আপনাকে কিছু ম্যাক্রো আর্গুমেন্টকে আরও শক্তিশালী করতে চাইলে এটিও সহায়তা করে

#include <cstdio>
#include <map>
#include <typeinfo>

#define STRV(...) #__VA_ARGS__
#define COMMA ,
#define FOO(type, bar) bar(STRV(type) \
    " has typeid name \"%s\"", typeid(type).name())

int main()
{
    FOO(std::map<int COMMA int>, std::printf);
}

যা কপি করে প্রিন্ট std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"


16
# নির্ধারিত COMAMA বাহ, আপনি আমাকে কেবলমাত্র ঘন্টাগুলি কাজ বাঁচিয়েছেন ... আমি কেন এই বছর আগে ভাবিনি। এই ধারণা ভাগ করার জন্য ধন্যবাদ। এটি এমনকি আমাকে ম্যাক্রোগুলি তৈরি করতে দেয় যা বিভিন্ন যুক্তির সাথে সেটআপ ফাংশনগুলি সম্পূর্ণ গণনা করে nts
মোলিয়াড


1
@kiw আপনি যদি #define STRVX(...) STRV(__VA_ARGS__)এবং #define STRV(...) # __VA_ARGS__তারপর, std::cout << STRV(type<A COMMA B>) << std::endl;প্রিন্ট হবে type<A COMMA B>এবং std::cout << STRVX(type<A COMMA B>) << std::endl;প্রিন্ট হবে type<A , B>। ( STRVএটি "ভ্যারিয়্যাডিক স্ট্রিংফাই" এর জন্য, এবং STRVXএটি "সম্প্রসারিত ভেরেনডিক স্ট্রিংফাইফাই" এর জন্য))
কোনও ব্যবহারকারী নয়

1
@ নন-এ-ইউজার হ্যাঁ, তবে ভ্যারিয়েডিক ম্যাক্রোগুলির সাথে আপনার COMMAপ্রথম স্থানে ম্যাক্রোর দরকার নেই । এটাই আমি শেষ করেছিলাম।
কিউ

আমি এটি কখনই ব্যবহার করি না, তবে হাসিখুশি হওয়ার জন্য +1 করতাম না।
রাফায়েল ব্যাপটিস্টা

58

যদি আপনার প্রিপ্রোসেসর ভেরিয়াদিক ম্যাক্রোগুলিকে সমর্থন করে:

#define SINGLE_ARG(...) __VA_ARGS__
#define FOO(type,name) type name

FOO(SINGLE_ARG(std::map<int, int>), map_var);

অন্যথায়, এটি কিছুটা ক্লান্তিকর:

#define SINGLE_ARG2(A,B) A,B
#define SINGLE_ARG3(A,B,C) A,B,C
// as many as you'll need

FOO(SINGLE_ARG2(std::map<int, int>), map_var);

ওহ, গোশ ... কেন? কেন শুধু বন্ধনী বন্ধ করা হয় না?

15
@ ভ্লাদলাজারেঙ্কো: কারণ আপনি সর্বদা কোডের স্বেচ্ছাসেবীকে বন্ধনীগুলিতে রাখতে পারবেন না। বিশেষত, আপনি কোনও ঘোষণাপত্রে টাইপের নামের চারপাশে প্রথম বন্ধনী রাখতে পারবেন না, যা এই যুক্তিটি হয়ে ওঠে।
মাইক সিমুর

2
... এবং এছাড়াও কারণ আপনি কেবল ম্যাক্রো সংজ্ঞাটি সংশোধন করতে সক্ষম হবেন এবং এটি কল করে এমন সমস্ত জায়গাই নয় (যা আপনার নিয়ন্ত্রণে নাও হতে পারে, বা ফাইলের বাকী অংশে ছড়িয়ে পড়ে থাকতে পারে ইত্যাদি)। এটি ঘটে, উদাহরণস্বরূপ, কোনও পছন্দ মতো কোনও ফাংশন থেকে দায়িত্ব গ্রহণের জন্য ম্যাক্রো যুক্ত করার সময়।
BeeOnRope

32

শুধু FOOহিসাবে সংজ্ঞায়িত করুন

#define UNPACK( ... ) __VA_ARGS__

#define FOO( type, name ) UNPACK type name

তারপরে এটি সর্বদা টাইপ আর্গুমেন্টের চারপাশে প্রথম বন্ধনীর সাথে অনুরোধ করুন

FOO( (std::map<int, int>), map_var );

ম্যাক্রো সংজ্ঞা সম্পর্কে একটি মন্তব্যে অনুরোধগুলির উদাহরণ দিয়ে দেওয়া অবশ্যই একটি ভাল ধারণা হতে পারে।


কেন এটি এত নিচে নেমেছে তা নিশ্চিত নন, এটি মাইক সিমোয়ার্সের চেয়ে অনেক সুন্দর সমাধান। এটি দ্রুত এবং সহজ এবং সম্পূর্ণরূপে ব্যবহারকারীর কাছ থেকে লুকানো।
iFreilicht

3
@ আইফ্রেইলিচট: এটি এক বছর পরে পোস্ট করা হয়েছিল। ;-)
চিয়ার্স এবং এইচটিএইচ। - আলফ

5
এবং কারণ এটি কীভাবে এবং কেন কাজ করে তা বোঝা শক্ত
ভিংগারিয়া

@ ভিনগার্কিয়া, আপনি ব্যাখ্যা করতে পারেন কেন / এটি কীভাবে কাজ করে? কেন এটি বন্ধ করার সময় প্রথম বন্ধনী প্রয়োজন? UNPACKএভাবে ব্যবহার করা হলে কী করবেন ) UNPACK type name? typeসঠিকভাবে টাইপটি ব্যবহার করার সময় কেন পাওয়া যায় ) UNPACK type name? এখানে কি ঘটছে?
ব্যবহারকারী


4

এটি করার জন্য কমপক্ষে দুটি উপায় রয়েছে। প্রথমত, আপনি এমন ম্যাক্রো সংজ্ঞায়িত করতে পারেন যা একাধিক যুক্তি গ্রহণ করে:

#define FOO2(type1, type2, name) type1, type2, name

যদি আপনি এটি করেন তবে আপনি খুঁজে পেতে পারেন যে আপনি আরও যুক্তি পরিচালনা করতে আরও ম্যাক্রো সংজ্ঞায়িত করেছেন।

দ্বিতীয়ত, আপনি যুক্তির আশেপাশে প্রথম বন্ধনী রাখতে পারেন:

#define FOO(type, name) type name
F00((std::map<int, int>) map_var;

যদি আপনি এটি করেন তবে আপনি দেখতে পাচ্ছেন যে অতিরিক্ত বন্ধনী ফলাফলের বাক্য গঠনটি স্ক্রু আপ করেছে।


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

4

P99 এর মাধ্যমে এটি সম্ভব :

#include "p99/p99.h"
#define FOO(...) P99_ALLBUTLAST(__VA_ARGS__) P99_LAST(__VA_ARGS__)
FOO()

উপরের কোডটি কার্যকরভাবে যুক্তি তালিকার শেষ কমাটি সরিয়ে ফেলে। clang -E(পি 99 এর একটি সি 99 সংকলক প্রয়োজন) সাথে চেক করুন ।


3

সহজ উত্তরটি আপনি পারবেন না। এটি <...>টেমপ্লেট আর্গুমেন্টগুলির পছন্দগুলির একটি পার্শ্ব প্রতিক্রিয়া ; <এবং >এছাড়াও ভারসাম্যহীন প্রেক্ষিতে প্রদর্শিত তাই ম্যাক্রো প্রক্রিয়া তাদের হ্যান্ডেল মত প্রথম বন্ধনী পরিচালনা বাড়ানো যাবে না। (কমিটির সদস্যদের মধ্যে কয়েকজন আলাদা টোকেনের পক্ষে যুক্তি দেখিয়েছিলেন, বলুন (^...^), তবে তারা বেশিরভাগ সমস্যা ব্যবহার করে বোঝাতে সক্ষম হননি <...>।)


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