मैं C ++ में फ़ंक्शन नाम के लिए अन्य नाम कैसे निर्दिष्ट करूं?


100

एक प्रकार, एक चर या नाम स्थान के लिए एक नया नाम बनाना आसान है। लेकिन मैं एक फ़ंक्शन को एक नया नाम कैसे दे सकता हूं? उदाहरण के लिए, मैं नाम का उपयोग करना चाहते hollerके लिए printf। # डेफिन स्पष्ट है ... कोई अन्य तरीका?

समाधान:

  1. #define holler printf
  2. void (*p)() = fn; //function pointer
  3. void (&r)() = fn; //function reference
  4. inline void g(){ f(); }

आप सभी को धन्यवाद। मेरे सहकर्मियों को void (&NewName)(some_vector&, float, float, float, float) = OldName;मेरा अगला चेक इन देखना पसंद है।
एगेल कुरियन

19
नहीं के रूप में ज्यादा के रूप में वे प्यार कर रहे हैं आप मानक पुस्तकालय कार्यों के लिए यादृच्छिक नाम का उपयोग कर प्यार करते हैं।
jalf

2
मैं printfयहां गड़बड़ नहीं कर रहा हूं । वह केवल एक उदाहरण था। यहाँ समस्या कुछ और की तुलना में अंग्रेजी की सीमाओं के साथ अधिक है। मेरा एक एकल कार्य उद्देश्य ए और उद्देश्य बी है, लेकिन मैं यहां दोनों उद्देश्यों की सेवा करने वाला एक भी नाम नहीं पा रहा हूं।
एगेल कुरियन

2
@ नील, ठीक है। T &a = b;के लिए एक नया नाम बनाता है btypedefप्रकार के लिए और namespace A=B;नाम स्थान के लिए।
एगनेल कुरियन

2
वहाँ है using BaseClass::BaseClassMethod, और वहाँ है using AliasType = Type;, और वहाँ भी है namespace AliasNamespace = Namespace;। जो हमें याद आ रहा हैusing AliasFunction = Function;
anton_rh

जवाबों:


114

अलग-अलग दृष्टिकोण हैं:

  • गैर-अतिभारित कार्यों के साथ C ++ 11 के साथ आप बस उपयोग कर सकते हैं:

    const auto& new_fn_name = old_fn_name;
  • यदि इस फ़ंक्शन में एकाधिक अधिभार हैं, तो आपको उपयोग करना चाहिए static_cast :

    const auto& new_fn_name = static_cast<OVERLOADED_FN_TYPE>(old_fn_name);

    उदाहरण: फ़ंक्शन के दो अधिभार हैं std::stoi

    int stoi (const string&, size_t*, int);
    int stoi (const wstring&, size_t*, int);

    यदि आप पहले संस्करण के लिए एक उपनाम बनाना चाहते हैं, तो आपको निम्नलिखित का उपयोग करना चाहिए:

    const auto& new_fn_name = static_cast<int(*)(const string&, size_t*, int)>(std::stoi);

    नोट: ओवरलोड फ़ंक्शन के लिए एक उपनाम बनाने का कोई तरीका नहीं है जैसे कि इसके सभी अतिभारित संस्करण काम करते हैं, इसलिए आपको हमेशा निर्दिष्ट करना चाहिए कि कौन सा सटीक फ़ंक्शन आपके द्वारा अधिभारित है।

  • C ++ 14 के साथ आप constexprटेम्प्लेट चर के साथ और भी आगे बढ़ सकते हैं । यह आपको अस्थायी कार्य करने की अनुमति देता है:

    template<typename T>
    constexpr void old_function(/* args */);
    
    template<typename T>
    constexpr auto alias_to_old = old_function<T>;
  • इसके अलावा, C ++ 11 से शुरू होने वाला एक फ़ंक्शन है जिसे कॉल किया जाता है std::mem_fnजो अन्य सदस्य कार्यों को करने की अनुमति देता है। निम्नलिखित उदाहरण देखें:

    struct A {
       void f(int i) {
          std::cout << "Argument: " << i << '\n';
       }
    };
    
    
    A a;
    
    auto greet = std::mem_fn(&A::f); // alias to member function
    // prints "Argument: 5"
    greet(a, 5); // you should provide an object each time you use this alias
    
    // if you want to bind an object permanently use `std::bind`
    greet_a = std::bind(greet, a, std::placeholders::_1);
    greet_a(3); // equivalent to greet(a, 3) => a.f(3);

1
बहुत बढ़िया, कैसे सी ++ 98 के बारे में? मेरे पास एक वर्ग w / 2 "रीसेट" है अधिभार सेट और रीसेट करने के लिए उपयोग किया जाता है। आंतरिक रूप से, कोई समस्या नहीं है। बाहरी उपयोगकर्ताओं के लिए मैं "सेट" के रूप में उर्फ ​​करना चाहता था, इसलिए यह संदर्भ के लिए सहज है (एक डिफ़ॉल्ट-निर्मित, स्पष्ट () डी आदि; कार्यशील रीसेट रीसेट करें)। कक्षा के तरीके: (1) "शून्य (और सेट) (कास्ट स्ट्रिंग और कास्ट, बस्ट, कास्ट बूल);" (2) शून्य (और सेट) (कास्ट स्ट्रिंग और कास्ट इंट, कास्ट बूल); 2 "रीसेट" w / संबंधित हस्ताक्षर काम करते हैं। चूँकि मेरे पास वर्ग घोषणा में हस्ताक्षर हैं, क्या मैं केवल कक्षा-आरंभ कर सकता हूँ: सेट (रीसेट), सेट (रीसेट)। यदि नहीं, तो क्या आपका स्पष्ट static_cast उदाहरण काम करेगा?
Luv2code

8
constexprटेम्पलेट चर दृष्टिकोण के साथ एक समस्या प्रतीत होती है : उपनाम प्रकार कटौती नहीं कर सकता। कंपाइलर को मुझे टेम्प्लेट पैरामीटर सूची प्रदान करने की आवश्यकता है (मैं एक वैरेडिक टेम्प्लेट फ़ंक्शन लिख रहा हूं): एक टेम्प्लेट तर्क तर्क सूची के बिना वैरिएबल टेम्प्लेट `अलियास_टो_ल्ड’ का संदर्भ नहीं दे सकता
user69818

1
constexpr auto new_fn_name = old_fn_nameC ++ 11 में काम करता है (कम से कम gcc 4.9.2 में) और रखने से बेहतर है &। इसे हमेशा पॉइंटर के माध्यम से कॉल करने की आवश्यकता नहीं होती है और इस प्रकार फ़ंक्शन को कॉल के स्थान पर इनबिल्ट करने की अनुमति मिलती है।
ony

C ++ 14 जेनेरिक लैंबडास के साथ, मैं निम्नलिखित कार्य करने में सक्षम था, जिसे तब भी काम करना चाहिए जब लक्ष्य फ़ंक्शन में कई अधिक भार हों: constexpr auto holler = [] ( auto &&...args ) { return printf( std::forward<decltype(args)>( args )... ); };
एंथनी हॉल

1
का उपयोग करना std::mem_fnहै नहीं एक उपनाम के बाद से यह भावना के पीछे भी बहुत कुछ जादू प्रदर्शन करती है।
cgsdfc

35

आप एक फ़ंक्शन पॉइंटर या फ़ंक्शन संदर्भ बना सकते हैं:

void fn()
{
}

//...

void (*p)() = fn;//function pointer
void (&r)() = fn;//function reference

2
यह केक लेता है। मैं फ़ंक्शन संदर्भों के बारे में नहीं जानता था।
एगेल कुरियन

@ वालकैन: वे लगभग एक जैसे हैं, आप दोनों को एक ही वाक्य रचना के साथ बुला सकते हैं, लेकिन उनके पते थोड़े अलग हैं। r अपनी खुद की मेमोरी स्पेस को एड्रेस नहीं बनाता है।
ब्रायन आर। बॉन्डी

1
आप कैसे कॉल करेंगे fn, उपनाम का उपयोग करके? क्या आप फ़ंक्शन पॉइंटर और फ़ंक्शन संदर्भ की व्याख्या कर सकते हैं? वे कैसे अलग हैं? क्या वे यहाँ भी वही हैं?
ma11hew28

1
@ मैट, आप इसे ठीक उसी तरह कहते हैं जैसे आप fn को कॉल करेंगे। r();
एगेल कुरियन

आप एक उदाहरण विधि के लिए यह कैसे करेंगे? संपादित करें: यह संकलन करने के लिए लगता है:void (&r)() = this->fn;
सैम

21
typedef int (*printf_alias)(const char*, ...);
printf_alias holler = std::printf;

क्या आपको ठीक करना चाहिए?


वैश्विक नाम स्थान में प्रिंट नहीं है?
एगेल कुरियन

3
यह वैश्विक है अगर आपने <stdio.h> को शामिल किया है, लेकिन std में यदि आपने <cstdio> शामिल किया है
Injektilo

@einpoklum: वहाँ के साथ कुछ भी नहीं गलत है decltype , लेकिन जवाब है से 2010 उस समय वहाँ नहीं था decltypeके रूप में यह C ++ 11 पेश किया गया था। इसके अलावा यह भी अच्छा पुराने सादा सी के साथ काम करना चाहिए
फिडेलक्स


7

एक इनलाइन आवरण का उपयोग करें। आप दोनों एपीआई प्राप्त करते हैं, लेकिन एकल कार्यान्वयन रखते हैं।


3

से fluentcpp : ALIAS_TEMPLATE_FUNCTION (च, छ)

#define ALIAS_TEMPLATE_FUNCTION(highLevelF, lowLevelF) \
template<typename... Args> \
inline auto highLevelF(Args&&... args) -> decltype(lowLevelF(std::forward<Args>(args)...)) \
{ \
    return lowLevelF(std::forward<Args>(args)...); \
}

0

यहां यह ध्यान देने योग्य है कि IMO जबकि मूल प्रश्न (और महान उत्तर) निश्चित रूप से उपयोगी हैं यदि आप किसी फ़ंक्शन का नाम बदलना चाहते हैं (ऐसा करने के लिए अच्छे कारण हैं!), यदि आप करना चाहते हैं तो एक गहरे नेमस्पेस को हटा दें लेकिन नाम रखें, इसके लिए usingकीवर्ड है:

namespace deep {
  namespace naming {
    namespace convention {
      void myFunction(int a, char b) {}
    }
  }
}
int main(void){
  // A pain to write it all out every time
  deep::naming::convention::myFunction(5, 'c');

  // Using keyword can be done this way
  using deep::naming::convention::myFunction;
  myFunction(5, 'c');  // Same as above
}

इसका एक फायदा यह भी है कि इसे एक दायरे तक ही सीमित रखा जा सकता है, हालाँकि आप इसे हमेशा किसी फ़ाइल के शीर्ष स्तर पर उपयोग कर सकते हैं। मैं अक्सर इसके लिए उपयोग करता हूं coutऔर endlइसलिए मुझे किसी फ़ाइल के शीर्ष पर सभी stdको क्लासिक के साथ लाने की आवश्यकता नहीं है using namespace std;, लेकिन यह उपयोगी भी है यदि आप std::this_thread::sleep_for()किसी फ़ाइल या फ़ंक्शन में बहुत कुछ उपयोग कर रहे हैं , लेकिन हर जगह नहीं, और नाम स्थान से कोई अन्य कार्य नहीं। हमेशा की तरह, इसे .h फ़ाइलों में उपयोग करने के लिए हतोत्साहित किया जाता है, या आप वैश्विक नाम स्थान को प्रदूषित करेंगे।

यह ऊपर दिए गए "नामकरण" के समान नहीं है, लेकिन अक्सर ऐसा होता है जो वास्तव में चाहता है।


0

C ++ 14 जेनेरिक लैंबडास के साथ, मैं निम्नलिखित कार्य करने में सक्षम था, जो तब भी काम करना चाहिए जब लक्ष्य फ़ंक्शन में कई लोड हो:

constexpr auto holler = [] ( auto &&...args ) {
        return printf( std::forward<decltype(args)>( args )... );
    };
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.