2012-02-03 5 views
11

क्या कोई सी ++ मैक्रो है जो वर्तमान नेमस्पेस और फ़ंक्शन नाम प्राप्त करता है? उदाहरण:मैक्रो वर्तमान नामस्थान और फ़ंक्शन नाम प्राप्त करने के लिए (लेकिन पूर्ण हस्ताक्षर नहीं)?

namespace foo { 
    namespace bar { 
    void baz(int i, double d) { 
     std::cout << MACRO << std::endl; 
    } 
    } 
} 

foo::bar::baz प्रिंट करेगा। मुझे __FUNCTION__ पता है लेकिन यह नामस्थान नहीं देता है। और BOOST_CURRENT_FUNCTION पूरे हस्ताक्षर देता है, सहित। तर्क और वापसी प्रकार:

void foo::bar::baz(int, double) 

हो सकता है, यह एक ऐसा मैक्रो नाम स्थान और BOOST_CURRENT_FUNCTION से समारोह नाम के अर्क लिखने के लिए संभव है?

मुझे लगता है कि प्रवेश के प्रयोजनों के लिए, की तरह

foo::bar::baz -- blah logging message blah 
+0

मुझे नहीं लगता कि फ़ंक्शन के पूर्ण हस्ताक्षर प्राप्त करने के लिए कोई प्लेटफार्म स्वतंत्र तरीका है। हालांकि, आप '__FILE__' और' __LINE__' के कॉम्बो का उपयोग क्यों नहीं कर सकते? यह आपको लगभग एक ही प्रभाव देगा; इसके अलावा एक फ़ंक्शन खोजने की तुलना में लॉग से आपके कोड में ढूंढने के लिए तेज़ है! – iammilind

+0

@iammilind: दरअसल, मैं log4cxx में लॉगर नाम के रूप में मैक्रो सामग्री का उपयोग करना चाहता हूं। उन लॉगर नाम पदानुक्रमित हैं और आप अलग-अलग नामस्थानों के लिए अलग-अलग लॉग स्तर सेट कर सकते हैं, इसलिए मैं वास्तव में क्या करता हूं जैसे 'log4cxx :: LoggerPtr लॉगर (log4cxx :: लॉगर :: getLogger ("foo.bar.baz")) ; LOG4CXX_INFO (लॉगर, "ब्ला लॉगिंग संदेश ब्लाह"); 'मैक्रो को' foo.bar.baz' भाग भरना चाहिए। मैं इसे अपनी पोस्ट में जटिल बनाना नहीं चाहता था। – Frank

उत्तर

4

एक प्रवेश स्ट्रिंग पाने के लिए जहां तक ​​मैं जानता हूँ कि चाहते हैं, यह संभव नहीं है (नहीं portably)। हालांकि पूर्ण हस्ताक्षर से आप उन तर्कों को निकाल सकते हैं। बेशक यह पार्स हस्ताक्षर कहा की आवश्यकता है ... जो इतना आसान नहीं है:

// What we want to consume: 
// void 
// signed short 
// unsigned int 
// Test::Bar<T, N> 
// 
static char const* consumeType(char const* const begin, char const* const end){ 
    static StringRef const Signed("signed"); 
    static StringRef const Unsigned("unsigned"); 

    char const* it = begin; 

    if (startsWith(it, Signed)) { it += Signed.size() + 1; } 
    else if (startsWith(it, Unsigned)) { it += Unsigned.size() + 1; } 

    // jump over the return type 
    size_t templateNest = 0; 
    while (it != end) { 
    if (*it == ' ' and templateNest == 0) { break; } 
    if (*it == '<') { ++templateNest; } 
    if (*it == '>' and templateNest > 0) { --templateNest; } 

    ++it; 
    } 

    return it; 
} // consumeType 

// 
// \param signature: signature as returned by __func___ on gcc 
// \return: full name, included namespace qualifier and class (if any) 
// 
// void Test::Bar<T, N>::parameterized(U) const 
// [with unsigned int O = 4u, U = Test::Foo, 
// T = Test::Foo, unsigned int N = 3u] 
// -> Test::Bar<T, N>::parameterized 
// 
StringRef parseFunctionName(StringRef const signature) { 
    char const* begin = signature.begin(); 
    char const* end = signature.end(); 

    // Jump over the return type 
    begin = consumeType(begin, end); 
    if (begin == end) { return signature; } 

    // skip the space right after the return type 
    ++begin; 
    if (begin == end) { return signature; } 

    // if we encounter a '(' then it means that we return a function, 
    // and we once again need to jump over the return type 
    if (*begin == '(') { 
    begin = consumeType(++begin, end); 

    // skip the space 
    ++begin; 
    if (begin == end) { return signature; } 
    } 

    // and finally, we got the beginning, and we need to get the end, which is 
    // the first opening '(' 
    char const* e = std::find(begin, end, '('); 
    return StringRef(begin, e - begin); 
} // parseFunctionName 

और इसकी accompagnying परीक्षण:

#define UT_FUNCTION_CHECK(Signature_, Name_) \ 
    UT_CHECK(parseFunctionName(StringRef(Signature_)) == Name_); 

void Function() { 
    // Regular functions 
    UT_FUNCTION_CHECK("int main()", "main") 
    UT_FUNCTION_CHECK("int foo(int, double)", "foo") 
    UT_FUNCTION_CHECK("unsigned int foo(int, double)", "foo") 

    // Templates 
    UT_FUNCTION_CHECK("unsigned int Test::Bar<T, N>::print() const" 
        " [with T = Test::Foo, unsigned int N = 3u]", 
        "Test::Bar<T, N>::print") 
    UT_FUNCTION_CHECK("Test::Bar<T, N> Test::Bar<T, N>::print() const" 
        " [with T = Test::Foo, unsigned int N = 3u]", 
        "Test::Bar<T, N>::print") 
    UT_FUNCTION_CHECK("void Test::Bar<T, N>::parameterized(U) const" 
        " [with unsigned int O = 4u, U = Test::Foo," 
        " T = Test::Foo, unsigned int N = 3u]", 
        "Test::Bar<T, N>::parameterized") 

    // Functions returning functions 
    UT_FUNCTION_CHECK("void (* Test::Foo::func() const)()", 
        "Test::Foo::func") 
    UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::method() const)(int)volatile", 
        "Test::Foo::method") 
    UT_FUNCTION_CHECK("void (Test::Foo::* Test::Foo::super())" 
        "(void (Test::Foo::*)(int)volatile)const", 
        "Test::Foo::super") 
    } // Function 

एक्स

यहाँ समारोह मैं इस समय का उपयोग है यह जीसीसी के __func__ मैक्रो के संयोजन में काम करता है।

StringRef कक्षा llvm::StringRef के समान है।

मुझे लगता है कि यदि आप अतिरिक्त पार्सिंग का जोखिम उठा सकते हैं तो मुझे आपकी ज़रूरतों को पूरा करना चाहिए। यह काफी तेज़ है: कोई बैकट्रैकिंग और गतिशील आवंटन नहीं, इसलिए कोई समस्या नहीं होनी चाहिए (विशेष रूप से फ़ाइल में लिखने की तुलना में ...)।

उम्मीद है कि यह मदद करता है।

+0

धन्यवाद! मैं इसे संकलित करने की कोशिश करूंगा। 'उपभोग टाइप' परिभाषित कैसे किया जाता है? – Frank

+1

@ फ्रैंक: मुझे सवाल समझ में नहीं आता है ... इसे उत्तर में लिखा गया है? –

+0

ओह, मेरी गलती, कभी नहीं। – Frank

संबंधित मुद्दे