আমি কীভাবে এমন একটি ফাংশন লিখতে পারি যা একটি পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করে? এটা কি সম্ভব?
আমি কীভাবে এমন একটি ফাংশন লিখতে পারি যা একটি পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করে? এটা কি সম্ভব?
উত্তর:
আপনার সম্ভবত করা উচিত নয় এবং আপনি সম্ভবত যা করতে চান তা নিরাপদ এবং সহজ উপায়ে করতে পারেন। প্রযুক্তিগতভাবে আপনি stdarg.h অন্তর্ভুক্ত সি মধ্যে পরিবর্তনশীল সংখ্যক আর্গুমেন্ট ব্যবহার করতে। থেকে আপনি পাবেন va_list
টাইপ সেইসাথে তিনটি কার্যকারিতা যে কাজ তে এটি বলা va_start()
, va_arg()
এবং va_end()
।
#include<stdarg.h>
int maxof(int n_args, ...)
{
va_list ap;
va_start(ap, n_args);
int max = va_arg(ap, int);
for(int i = 2; i <= n_args; i++) {
int a = va_arg(ap, int);
if(a > max) max = a;
}
va_end(ap);
return max;
}
আপনি যদি আমাকে জিজ্ঞাসা করেন, এটি একটি গোলযোগ। এটি দেখতে খারাপ লাগছে, এটি অনিরাপদ এবং এটি প্রযুক্তিগত বিবরণ দিয়ে পূর্ণ যা আপনি ধারণাগতভাবে অর্জন করার চেষ্টা করছেন তার সাথে কিছুই করার নেই। পরিবর্তে, ওভারলোডিং বা উত্তরাধিকার / পলিমারফিজম, বিল্ডার প্যাটার্ন (যেমন operator<<()
স্ট্রিমগুলির মধ্যে) বা ডিফল্ট আর্গুমেন্ট ইত্যাদি ব্যবহারের বিষয়ে বিবেচনা করুন all এগুলি আরও সুরক্ষিত: সংকলকটি আপনি কী করার চেষ্টা করছেন সে সম্পর্কে আরও জানতে পারবেন যাতে আরও কিছু ঘটনা বন্ধ হতে পারে more তুমি তোমার পা উড়িয়ে দেওয়ার আগে
...
সিনট্যাক্সের আগে কমপক্ষে একটি যুক্তি সরবরাহ করা কি প্রয়োজনীয় ?
printf()
, উদাহরণস্বরূপ, ফাংশন কত অতিরিক্ত আর্গুমেন্ট এটা পরিবর্তনশীল যুক্তি তালিকায় আশা করা উচিত জিনিসটা বিশেষ টোকেন জন্য স্ট্রিং যুক্তি parses।
<cstdarg>
সি ++ এর পরিবর্তে<stdarg.h>
ইন সি ++ 11 আপনি দুটি নতুন অপশন আছে, Variadic ফাংশন রেফারেন্স পৃষ্ঠা বিকল্প ধারা বলে:
- ভেরিয়েডিক টেম্পলেটগুলি এমন ফাংশন তৈরি করতেও ব্যবহৃত হতে পারে যা পরিবর্তনশীল সংখ্যক আর্গুমেন্ট গ্রহণ করে। এগুলি প্রায়শই ভাল পছন্দ কারণ তারা যুক্তির ধরণের প্রকারের উপর বিধিনিষেধ আরোপ করে না, অবিচ্ছেদ্য এবং ভাসমান-পয়েন্ট প্রচার করে না এবং সুরক্ষিত থাকে। (যেহেতু সি ++ ১১)
- যদি সমস্ত ভেরিয়েবল আর্গুমেন্ট একটি সাধারণ ধরণের ভাগ করে দেয় তবে একটি স্টাডি :: আরম্ভকারী_লিস্ট ভেরিয়েবল আর্গুমেন্ট অ্যাক্সেসের জন্য একটি সুবিধাজনক প্রক্রিয়া সরবরাহ করে (যদিও আলাদা সিনট্যাক্স সহ)।
নীচে উভয় বিকল্প দেখানোর একটি উদাহরণ দেওয়া হয়েছে ( এটি সরাসরি দেখুন ):
#include <iostream>
#include <string>
#include <initializer_list>
template <typename T>
void func(T t)
{
std::cout << t << std::endl ;
}
template<typename T, typename... Args>
void func(T t, Args... args) // recursive variadic function
{
std::cout << t <<std::endl ;
func(args...) ;
}
template <class T>
void func2( std::initializer_list<T> list )
{
for( auto elem : list )
{
std::cout << elem << std::endl ;
}
}
int main()
{
std::string
str1( "Hello" ),
str2( "world" );
func(1,2.5,'a',str1);
func2( {10, 20, 30, 40 }) ;
func2( {str1, str2 } ) ;
}
আপনি যদি ব্যবহার করছেন gcc
বা clang
আমরা PRETTY_FUNCTION ম্যাজিক ভেরিয়েবলটি ফাংশনের প্রকারের স্বাক্ষর প্রদর্শন করতে পারি যা যা চলছে তা বুঝতে সহায়তা করতে পারে। উদাহরণস্বরূপ:
std::cout << __PRETTY_FUNCTION__ << ": " << t <<std::endl ;
উদাহরণে বৈকল্পিক ফাংশনগুলির জন্য নিম্নলিখিত ফলাফলের ফলাফল হবে ( এটি সরাসরি দেখুন ):
void func(T, Args...) [T = int, Args = <double, char, std::basic_string<char>>]: 1
void func(T, Args...) [T = double, Args = <char, std::basic_string<char>>]: 2.5
void func(T, Args...) [T = char, Args = <std::basic_string<char>>]: a
void func(T) [T = std::basic_string<char>]: Hello
ভিজ্যুয়াল স্টুডিওতে আপনি ফুনসিএসআইজি ব্যবহার করতে পারেন ।
প্রি সি সি ++ 11 আপডেট করুন
প্রাক সি ++ 11 জন্য বিকল্প এসটিডি :: initializer_list হবে এসটিডি :: ভেক্টর বা অন্যান্য এক মান পাত্রে :
#include <iostream>
#include <string>
#include <vector>
template <class T>
void func1( std::vector<T> vec )
{
for( typename std::vector<T>::iterator iter = vec.begin(); iter != vec.end(); ++iter )
{
std::cout << *iter << std::endl ;
}
}
int main()
{
int arr1[] = {10, 20, 30, 40} ;
std::string arr2[] = { "hello", "world" } ;
std::vector<int> v1( arr1, arr1+4 ) ;
std::vector<std::string> v2( arr2, arr2+2 ) ;
func1( v1 ) ;
func1( v2 ) ;
}
এবং জন্য বিকল্প variadic টেমপ্লেট হবে variadic ফাংশন যদিও তারা হয় না টাইপ-নিরাপদ এবং সাধারণভাবে ত্রুটি প্রবণ এবং ব্যবহার করা অনিরাপদ হতে পারে কিন্তু শুধুমাত্র অন্যান্য সম্ভাব্য বিকল্প ব্যবহার করতে হবে ডিফল্ট আর্গুমেন্ট , যদিও যে সীমিত ব্যবহারের হয়েছে। নীচের উদাহরণটি লিঙ্কযুক্ত রেফারেন্সে নমুনা কোডের একটি পরিবর্তিত সংস্করণ:
#include <iostream>
#include <string>
#include <cstdarg>
void simple_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
while (*fmt != '\0') {
if (*fmt == 'd') {
int i = va_arg(args, int);
std::cout << i << '\n';
} else if (*fmt == 's') {
char * s = va_arg(args, char*);
std::cout << s << '\n';
}
++fmt;
}
va_end(args);
}
int main()
{
std::string
str1( "Hello" ),
str2( "world" );
simple_printf("dddd", 10, 20, 30, 40 );
simple_printf("ss", str1.c_str(), str2.c_str() );
return 0 ;
}
ব্যবহার variadic ফাংশন এছাড়াও আর্গুমেন্ট আপনি পাস করতে পারেন, যা বিস্তারিত হয় বিধিনিষেধ দিয়ে আসে খসড়া C ++ স্ট্যান্ডার্ডের অধ্যায় 5.2.2
ফাংশন কল অনুচ্ছেদ 7 :
যখন কোনও প্রদত্ত আর্গুমেন্টের জন্য কোনও প্যারামিটার না থাকে তখন আর্গুমেন্টটি এমনভাবে পাস করা হয় যাতে প্রাপ্ত ফাংশনটি ভায়ার্গ (18.7) দিয়ে আর্গুমেন্টের মান অর্জন করতে পারে। লভ্যু-টু-রেভ্যালু (৪.১), অ্যারে-টু-পয়েন্টার (৪.২) এবং ফাংশন-টু-পয়েন্টার (৪.৩) স্ট্যান্ডার্ড রূপান্তরগুলি আর্গুমেন্টের অভিব্যক্তিতে সঞ্চালিত হয়। এই রূপান্তরগুলির পরে, যদি যুক্তিতে গাণিতিক, গণনা, পয়েন্টার, পয়েন্টার অফ মেম্বার বা শ্রেণীর ধরণ না থাকে তবে প্রোগ্রামটি দুর্গঠিত। যদি আর্গুমেন্টটির কোনও POD বিবিধ শ্রেণি থাকে (ধারা 9), আচরণটি অপরিজ্ঞাত। [...]
typename
বনাম class
ব্যবহার উপরে উদ্দেশ্যমূলক? যদি তা হয় তবে দয়া করে ব্যাখ্যা করুন।
initializer_list
পুনরাবৃত্তি গ্রহণ করে কোনও ফাংশন করা কি সম্ভব ?
যেহেতু সি ++ 11 এ ভেরিয়ডিক টেম্পলেটগুলির প্রবর্তন এবং সি ++ 17 এ ফোল্ডার এক্সপ্রেশনগুলি সংযুক্ত করা সম্ভব, তাই কলকারী সাইটে কল করা যায় এমন একটি টেমপ্লেট-ফাংশনটি সংজ্ঞায়িত করা সম্ভব যে এটি কোনও বৈকল্পিক ফাংশন ছিল তবে তার সুবিধার সাথে :
মিশ্র যুক্তি প্রকারের জন্য এখানে একটি উদাহরণ is
template<class... Args>
void print(Args... args)
{
(std::cout << ... << args) << "\n";
}
print(1, ':', " Hello", ',', " ", "World!");
এবং আরও কার্যকরভাবে যুক্তিযুক্ত সমস্ত যুক্তির সাথে মেলে:
#include <type_traits> // enable_if, conjuction
template<class Head, class... Tail>
using are_same = std::conjunction<std::is_same<Head, Tail>...>;
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
void print_same_type(Head head, Tail... tail)
{
std::cout << head;
(std::cout << ... << tail) << "\n";
}
print_same_type("2: ", "Hello, ", "World!"); // OK
print_same_type(3, ": ", "Hello, ", "World!"); // no matching function for call to 'print_same_type(int, const char [3], const char [8], const char [7])'
// print_same_type(3, ": ", "Hello, ", "World!");
^
অধিক তথ্য:
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
এবং যদি Tail...
একই হয় ", যেখানে " একই " মানে হয় std::conjunction<std::is_same<Head, Tail>...>
। এই সর্বশেষ Head
নির্ধারণটি Tail...
" সকলের সমান " হিসাবে পড়ুন ।
সি ++ 11 এ আপনি করতে পারেন:
void foo(const std::list<std::string> & myArguments) {
//do whatever you want, with all the convenience of lists
}
foo({"arg1","arg2"});
এফটিডব্লিউ তালিকা!
সি ++ ১১-এ ভেরিয়েবল আর্গুমেন্ট টেম্পলেটগুলি করার একটি উপায় রয়েছে যা ভেরিয়েবল আর্গুমেন্ট ফাংশনগুলি রাখতে সত্যই মার্জিত এবং টাইপ সুরক্ষিত পথে পরিচালিত করে। বিয়ারনে নিজে একটি চমৎকার উদাহরণ দেয় পরিবর্তনশীল যুক্তি টেমপ্লেটগুলি ব্যবহার printf, মধ্যে সি ++ 11FAQ ।
ব্যক্তিগতভাবে, আমি এটিকে এত মার্জিত বিবেচনা করি যে সি ++ এর মধ্যে একটি পরিবর্তনশীল যুক্তি ফাংশন নিয়েও আমি বিরক্ত করব না যতক্ষণ না এই সংকলকটির সি ++ 11 ভেরিয়েবল আর্গুমেন্ট টেম্পলেটগুলির সমর্থন না থাকে।
,
ভাঁজ প্রকাশের সাথে অপারেটরটি ব্যবহার করতে পারেন )। অন্যথায়, আমি এটি মনে করি না।
সি স্টাইলের ভেরিয়াদিক ফাংশন সি ++ এ সমর্থিত।
তবে বেশিরভাগ সি ++ লাইব্রেরি বিকল্প আইডিয়াম ব্যবহার করে যেমন 'c' printf
ফাংশনটি ভেরিয়েবল আর্গুমেন্ট গ্রহণ করে যা c++ cout
বস্তু <<
ওভারলোডিং ব্যবহার করে যা প্রকারের সুরক্ষা এবং এডিটিগুলিকে সম্বোধন করে (সম্ভবত বাস্তবায়নের সরলতার জন্য ব্যয় করে)।
std::initializer_lists
... এবং এটি ইতিমধ্যে একটি সহজ কাজটিতে ব্যাপক জটিলতা প্রবর্তন করছে।
ভারার্গস বা ওভারলোডিং ছাড়াও, আপনি আপনার যুক্তিগুলি স্টাড :: ভেক্টর বা অন্যান্য পাত্রে (উদাহরণস্বরূপ মানচিত্র: মানচিত্র) একত্রিত করার বিষয়ে বিবেচনা করতে পারেন। এটার মতো কিছু:
template <typename T> void f(std::vector<T> const&);
std::vector<int> my_args;
my_args.push_back(1);
my_args.push_back(2);
f(my_args);
এইভাবে আপনি প্রকারের সুরক্ষা পাবেন এবং এই বৈকল্পিক যুক্তিগুলির যৌক্তিক অর্থ স্পষ্ট হবে।
অবশ্যই এই পদ্ধতির পারফরম্যান্স সংক্রান্ত সমস্যা থাকতে পারে তবে আপনি মূল্য পরিশোধ করতে পারবেন না তা নিশ্চিত হওয়া পর্যন্ত আপনি সেগুলি নিয়ে চিন্তা করবেন না। এটি সি ++ এর এক ধরণের "পাইথোনিক" পদ্ধতির ...
একমাত্র উপায় হ'ল এখানে বর্ণিত হিসাবে সি স্টাইলের ভেরিয়েবল আর্গুমেন্ট ব্যবহার । মনে রাখবেন যে এটি কোনও প্রস্তাবিত অনুশীলন নয়, কারণ এটি টাইপসেফ এবং ত্রুটি-প্রবণ নয়।
সি-স্টাইলের ভারার্গস ( ...
) অবলম্বন না করে এটি করার কোনও মানক সি ++ উপায় নেই ।
অবশ্যই ডিফল্ট আর্গুমেন্ট রয়েছে যা প্রসঙ্গে নির্ভর করে তাত্ক্ষণিক সংখ্যার মতো "চেহারা" সাজায়:
void myfunc( int i = 0, int j = 1, int k = 2 );
// other code...
myfunc();
myfunc( 2 );
myfunc( 2, 1 );
myfunc( 2, 1, 0 );
চারটি ফাংশন কল myfunc
বিভিন্ন সংখ্যক যুক্তি সহ কল করে। যদি কিছু না দেওয়া হয় তবে ডিফল্ট আর্গুমেন্ট ব্যবহার করা হয়। তবে নোট করুন, আপনি কেবল অনুগ্রহযোগ্য আর্গুমেন্ট বাদ দিতে পারেন। কোনও উপায় নেই, উদাহরণস্বরূপ বাদ দেওয়া i
এবং দেওয়ার জন্য j
।
এটি সম্ভব যে আপনি ওভারলোডিং বা ডিফল্ট পরামিতিগুলি চান - ডিফল্ট পরামিতিগুলির সাথে একই ফাংশনটি সংজ্ঞায়িত করুন:
void doStuff( int a, double termstator = 1.0, bool useFlag = true )
{
// stuff
}
void doStuff( double std_termstator )
{
// assume the user always wants '1' for the a param
return doStuff( 1, std_termstator );
}
এটি আপনাকে চারটি আলাদা আলাদা কলের মাধ্যমে পদ্ধতিটিতে কল করতে দেয়:
doStuff( 1 );
doStuff( 2, 2.5 );
doStuff( 1, 1.0, false );
doStuff( 6.72 );
... অথবা আপনি সি এর থেকে v_args আহ্বানের সম্মেলন সন্ধান করতে পারেন
যদি আপনি সরবরাহ করা হবে যে সংখ্যার আর্গুমেন্টের পরিধিটি জানেন তবে আপনি সর্বদা কিছু ফাংশন ওভারলোডিং ব্যবহার করতে পারেন, যেমন
f(int a)
{int res=a; return res;}
f(int a, int b)
{int res=a+b; return res;}
এবং তাই ...
বৈচিত্র্যমূলক টেম্পলেটগুলি ব্যবহার করে উদাহরণস্বরূপ console.log
জাভাস্ক্রিপ্টে দেখা গেছে পুনরুত্পাদন :
Console console;
console.log("bunch", "of", "arguments");
console.warn("or some numbers:", 1, 2, 3);
console.error("just a prank", "bro");
ফাইলের নাম যেমন js_console.h
:
#include <iostream>
#include <utility>
class Console {
protected:
template <typename T>
void log_argument(T t) {
std::cout << t << " ";
}
public:
template <typename... Args>
void log(Args&&... args) {
int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
cout << endl;
}
template <typename... Args>
void warn(Args&&... args) {
cout << "WARNING: ";
int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
cout << endl;
}
template <typename... Args>
void error(Args&&... args) {
cout << "ERROR: ";
int dummy[] = { 0, ((void) log_argument(std::forward<Args>(args)),0)... };
cout << endl;
}
};
অন্যরা যেমন বলেছে, সি-স্টাইলের ভ্যারাগস। তবে আপনি ডিফল্ট যুক্তিগুলির সাথেও অনুরূপ কিছু করতে পারেন।
এটি এখনই সম্ভব ... বুস্ট যেকোন এবং টেম্পলেট ব্যবহার করে এই ক্ষেত্রে, আর্গুমেন্টের প্রকারটি মিশ্রিত করা যেতে পারে
#include <boost/any.hpp>
#include <iostream>
#include <vector>
using boost::any_cast;
template <typename T, typename... Types>
void Alert(T var1,Types... var2)
{
std::vector<boost::any> a( {var1,var2...});
for (int i = 0; i < a.size();i++)
{
if (a[i].type() == typeid(int))
{
std::cout << "int " << boost::any_cast<int> (a[i]) << std::endl;
}
if (a[i].type() == typeid(double))
{
std::cout << "double " << boost::any_cast<double> (a[i]) << std::endl;
}
if (a[i].type() == typeid(const char*))
{
std::cout << "char* " << boost::any_cast<const char*> (a[i]) <<std::endl;
}
// etc
}
}
void main()
{
Alert("something",0,0,0.3);
}
শব্দার্থগতভাবে সহজতম, পারফরম্যান্ট এবং সর্বাধিক গতিশীল বিকল্পের জন্য সি এবং সি ++ সমাধানগুলি একত্রিত করুন। যদি আপনি ভুল করে থাকেন তবে অন্য কিছু চেষ্টা করুন।
// spawn: allocate and initialize (a simple function)
template<typename T>
T * spawn(size_t n, ...){
T * arr = new T[n];
va_list ap;
va_start(ap, n);
for (size_t i = 0; i < n; i++)
T[i] = va_arg(ap,T);
return arr;
}
ব্যবহারকারী লিখেছেন:
auto arr = spawn<float> (3, 0.1,0.2,0.3);
শব্দার্থকভাবে, এটি দেখতে একটি এন-আর্গুমেন্ট ফাংশনের মতো দেখতে এবং অনুভব করা। হুডের নীচে, আপনি এটিকে কোনও উপায়ে বা অন্য কোনও উপায়ে আনতে পারবেন।
int fun(int n_args, ...) {
int *p = &n_args;
int s = sizeof(int);
p += s + s - 1;
for(int i = 0; i < n_args; i++) {
printf("A1 %d!\n", *p);
p += 2;
}
}
সরল সংস্করণ