संकलन समय पर सुनिश्चित करें कि एक विधि को एक ही स्थान पर कहा जाता है


15

मैं इस बात को लेकर उत्सुक हूं कि क्या संकलन के समय यह सुनिश्चित करना संभव है कि किसी विधि को एक स्थान पर बुलाया जाए।

ध्यान दें कि यदि फ़ंक्शन को एक से अधिक बार (जैसे लूप में) कहा जाता है तो यह ठीक है - लेकिन इसे दो अलग-अलग छोरों में नहीं बुलाया जाना चाहिए।

इसे दो भागों में तोड़ा जा सकता है, मुझे उन समाधानों में भी दिलचस्पी है जो किसी भी हिस्से को कवर करते हैं:
(ए) सुनिश्चित करें कि एक विधि को कम से कम एक जगह कहा जाता है
(बी) सुनिश्चित करें कि एक विधि को एक ही स्थान पर बुलाया जाता है

कोड की संरचना पर मेरा पूर्ण नियंत्रण है, और समान विचार प्राप्त करने वाले विभिन्न मुहावरे स्वागत योग्य हैं।

// class.h

class MyClass {
  public:
    void my_method();
}

निम्नलिखित को संकलित नहीं किया जाना चाहिए (कभी नहीं कहा जाता है)

#include "class.h"

int main() {
  MyClass my_class;
}

निम्नलिखित को संकलित नहीं किया जाना चाहिए (एक से अधिक स्थानों में कहा जाता है)

#include "class.h"

int main() {
  MyClass my_class;
  my_class.my_method();
  while(true) {
    my_class.my_method();
  }
}

निम्नलिखित को संकलित किया जाना चाहिए (वास्तव में एक ही स्थान पर):

#include "class.h"

int main() {
  MyClass my_class;
  while(true) {
    my_class.my_method();
  }
}

2
इसे एक विधि मत बनाओ। कोड इनलाइन को उस एक स्थान पर रखें।
user207421

2
मुझे लगता है कि आप एक लंबोदर के साथ भी ऐसा कर सकते हैं (यह एक खाली भेड़ का बच्चा हो सकता है) क्योंकि प्रत्येक मेमने के लिए एक करीबी का प्रकार अद्वितीय है। फिर, यह एक रनटाइम त्रुटि होगी लेकिन आपने जो मांगा है वह नहीं है। यदि आप उस समस्या के बारे में अधिक विवरण प्रदान करते हैं जिसे आप हल करने का प्रयास कर रहे हैं, तो हम इसके चारों ओर एक रास्ता खोजने में सक्षम हो सकते हैं।
इंडियाना कर्निक

2
आप ऐसा करने के लिए गैर-मानक __COUNTER__मैक्रो का उपयोग कर सकते हैं । कुछ इस तरह static_assert(__COUNTER__ == 0); my_class.my_method();। हालाँकि, काउंटर प्रत्येक अनुवाद इकाई में रहता है, इसलिए आप केवल जाँच सकते हैं कि फ़ंक्शन को एक बार प्रति अनुवाद इकाई कहा जाता है।
इंडियाना केर्निक

4
तुम ऐसा क्यों करना चाहते हो। एक समारोह के बिंदु का हिस्सा यह है कि इसे कई स्थानों से बुलाया जा सकता है।
चीपस्टर

4
आपको यह समझाना चाहिए कि आप ऐसा क्यों करना चाहते हैं। हो सकता है कि आप जो समाधान पूछ रहे हैं, वह आपके वास्तविक लक्ष्यों को पूरा करने के लिए सबसे अच्छा न हो।
दस

जवाबों:


6

निम्न तकनीक दृष्टिकोण:

चूँकि आपके पास कोड संरचना पर नियंत्रण है (जिसमें निर्माण प्रणाली भी शामिल है, मुझे लगता है), यहाँ एक कम तकनीकी समाधान है:

  • फ़ंक्शन का नाम पर्याप्त रूप से विशिष्ट बनाएं
  • अपने कोड में फ़ंक्शन नाम के लिए grep। आप इसे दो बार उम्मीद कर रहे हैं (यह मानते हुए कि आप घोषणा और परिभाषा को शांत कर रहे हैं):
    • एक बार हेडर में
    • एक बार सिंगल कॉल साइट पर

वैकल्पिक रूप से:

यदि आप वास्तव में, वास्तव में, वास्तव में सी ++ के साथ इसे हल करना चाहते हैं, तो आप कोशिश कर सकते हैं

  • एक संकलन इकाइयों के भीतर उपयोगों की संख्या जानने के लिए एक संकलन समय काउंटर का उपयोग करें
  • सुनिश्चित करें कि यदि हेडर कई संकलन इकाइयों में शामिल है तो फ़ंक्शन ODR का उल्लंघन करेगा।

हालांकि, संकलन समय काउंटर काला जादू हैं (I, और मुझे वास्तव में TMP पसंद है), और इस उद्देश्य के लिए ODR उल्लंघन करने के लिए ऐसा लगता है कि समान वूडू (कम से कम आपको एक परीक्षण मामले की आवश्यकता होगी जो लिंक करने में विफल हो)।

परन्तु गंभीरता से:

यह मत करो। आप जो कुछ भी करते हैं, वह एक आवरण फ़ंक्शन द्वारा लगभग कोई प्रयास के साथ विकृत हो सकता है:

auto call_my_method(MyClass& o)
{
   return o.my_method();
}

MyClass::my_method()केवल आवरण में कहा जाता है। हर कोई बस रैपर को कॉल करता है जो शायद संकलक द्वारा भी इनबिल्ड है।

जैसा कि अन्य लोगों ने सुझाव दिया है: यह बहुत अधिक सहायक हो सकता है यदि आप बताएंगे कि आप क्या करने की कोशिश कर रहे हैं।


1

यहां एक मोटा विचार है जो काम कर सकता है (एक टिप्पणी के लिए बहुत लंबा - लेकिन एक अच्छा एसओ उत्तर के लिए अधूरा)।

आप टेम्पलेट तात्कालिकताओं की गणना / जाँच करके इसे प्राप्त करने में सक्षम हो सकते हैं। उपयोग के बाद
ही टेम्प्लेट का त्वरित मूल्यांकन किया जाता है

इसी तरह, टेम्प्लेट मेथड / फंक्शन बॉडीज़ को पार्स नहीं किया जाता है और न ही संकलित या लिंक किया जाता है (वैध सिंटैक्स सुनिश्चित करने से परे) यदि उन्हें कभी नहीं कहा जाता है। इसका मतलब यह है कि उनके शरीर के भीतर कोई तात्कालिकता नहीं बनती है)।

आप एक ऐसा टेम्प्लेट बनाने में सक्षम हो सकते हैं जो कुछ वैश्विक तात्कालिकता गणना और उस पर स्थिर अभिकर्मक (या किसी अन्य टीएमपी तंत्र को पिछले तात्कालिकता की जांच करने के लिए) बनाए रखता है।


"वैश्विक" तात्कालिकता गणना वर्तमान संकलन इकाई के लिए स्थानीय होगी।
एटॉमसिमबोल

1

C प्रीप्रोसेसर और GNU इनलाइन असेंबली का उपयोग करके इस प्रश्न का आंशिक समाधान है:

हैडर फ़ाइल a.h:

struct A {
    // Do not call this method directly, use the macro below to call it
    int _method_vUcaJB5NKSD3upQ(int i, int j);
};

// Use inline assembly to ensure that this macro is used at most once
#define method_vUcaJB5NKSD3upQ(args...) \
    _method_vUcaJB5NKSD3upQ(args); \
    asm (".global once_vUcaJB5NKSD3upQ; once_vUcaJB5NKSD3upQ:");

कार्यान्वयन फ़ाइल a.cc:

#include <iostream>
#include "a.h"

int A::_method_vUcaJB5NKSD3upQ(int i, int j) { return i+j+5; }

// Ensure that the macro is used at least once
extern "C" const char once_vUcaJB5NKSD3upQ;
static const char get_vUcaJB5NKSD3upQ = once_vUcaJB5NKSD3upQ;

int main() {
    A a;
    for(int i=0; i<7; i++) {
        // Use a separate statement to call the method
        // (terminated by a semicolon, it cannot be a sub-expression)
        auto x = a.method_vUcaJB5NKSD3upQ(2, 3);
        std::cout << x << std::endl;
    }
    return 0;
}

यह समाधान इस अर्थ में आंशिक है कि यह आवरण मैक्रो का उपयोग किए बिना प्रोग्राम को सीधे अंडरस्कोर के साथ शुरू करने के लिए प्रोग्राम को रोकने के लिए नहीं रोकता है।


0

एक constexpr काउंटर का उपयोग करें। एक अन्य प्रश्न में एक कार्यान्वयन है


1
ऐसा लगता है कि यह विधि बीमार है।
चिपस्टर

इस मुद्दे को open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118 ने इस प्रश्न के उत्तर में संदर्भित किया है कि यह मानक की एक बग है और इसे बीमार बनाया जाना चाहिए।
SD57

तो यह बीमार नहीं है, कम से कम अभी तक नहीं?
चिपस्टर

यदि यह अभी तक बीमार नहीं है, तो इसका उपयोग यथासंभव अधिक से अधिक लोगों द्वारा किया जाना चाहिए, ताकि उन्हें इस उपयोग के मामले का समर्थन करना पड़े!
user1685095
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.