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

constexpr size_t my_strlen(const char* s)
{
        const char* cp = s;
        while(*cp != '\0') { cp++; };
        return cp - s;
}

और अब मैं चाहता हूँ:

template <typename T>
constexpr auto type_name_length = my_strlen(typeid(T).name());

लेकिन अफसोस, typeid(T).name() सिर्फ const char* है, कॉन्स्टेक्स नहीं...

37
einpoklum 11 मार्च 2016, 16:06
आप type_name_length<T> के साथ क्या करना चाहते हैं जिसकी आपको संकलन समय पर आवश्यकता है? कंपाइलर केवल strlen() का मूल्यांकन करने और यदि संभव हो तो आपको स्थिरांक देने के बारे में बहुत अच्छे हैं।
 – 
Barry
11 मार्च 2016, 17:13
@ बैरी: मैं बस यहां एक एमसीवीई चाहता था, इसलिए मैंने सिंथेटिक उपयोग किया।
 – 
einpoklum
11 मार्च 2016, 17:19
यह अच्छा है; लेकिन यह कहते हुए एक टिप्पणी जोड़ना कि प्रश्न में (यह केवल एक एमसीवीई है, मैं वास्तव में एक्स की कोशिश कर रहा हूं) भी अच्छा है।
 – 
Yakk - Adam Nevraumont
11 मार्च 2016, 22:25
@Yakk: मैंने कहा "उदाहरण के लिए" और "मान लीजिए" ...
 – 
einpoklum
11 मार्च 2016, 22:30
1
@Yakk: यह कुछ CUDA डिवाइस-साइड डिबगिंग कोड के लिए था जो टाइप नाम प्रिंट करता है लेकिन आउटपुट को संरेखित करने की भी आवश्यकता होती है, और मैं लंबाई की गणना करने के लिए लूप के बिना प्रिंटफ स्टेटमेंट में सबकुछ फिट करना चाहता था।
 – 
einpoklum
12 सितंबर 2016, 09:48

2 जवाब

ठीक है, आप कर सकते हैं, की तरह, लेकिन शायद काफी पोर्टेबल नहीं:

struct string_view
{
    char const* data;
    std::size_t size;
};

inline std::ostream& operator<<(std::ostream& o, string_view const& s)
{
    return o.write(s.data, s.size);
}

template<class T>
constexpr string_view get_name()
{
    char const* p = __PRETTY_FUNCTION__;
    while (*p++ != '=');
    for (; *p == ' '; ++p);
    char const* p2 = p;
    int count = 1;
    for (;;++p2)
    {
        switch (*p2)
        {
        case '[':
            ++count;
            break;
        case ']':
            --count;
            if (!count)
                return {p, std::size_t(p2 - p)};
        }
    }
    return {};
}

और आप अपने वांछित type_name_length को इस प्रकार परिभाषित कर सकते हैं:

template <typename T>
constexpr auto type_name_length = get_name<T>().size;

DEMO (क्लैंग और g++ के लिए काम करता है)

97
Jamboree 11 मार्च 2016, 18:12
3
एमएसवीसी पर __FUNCSIG__ के साथ कुछ ऐसा ही लागू किया जा सकता है।
 – 
melak47
11 मार्च 2016, 18:18
मुझे यह साइट मिली और मैंने __FUNCSIG__ का परीक्षण किया। ऐसा लगता है कि जीसीसी के हाइब्रिड आउटपुट के विपरीत, पूरी तरह से प्रतिस्थापित/बाध्य प्रकारों को उत्सर्जित करता है, जैसे कि फ़ंक्शन को स्पष्ट रूप से तत्काल चालू किया गया था। उदाहरण के लिए: void __cdecl foo<double>(const double &), जो एक नज़र में मेरे लिए कम उपयोगी लगता है। (जीसीसी अभी भी आश्रित बनाम मुक्त प्रकारों के बीच कुछ अजीब अंतर करता है, या शायद घटाया बनाम गणना प्रकार, जब प्रतिस्थापन प्रदर्शन करते हैं।) मुझे लगता है कि प्रतिबिंब अत्यधिक कम और कम समर्थित है, esp। अवधारणाओं के साथ अब तक क्षितिज पर ...
 – 
John P
26 पद 2017, 18:21
@ जॉनपी: क्या आपको लगता है कि आप इसे प्रस्तावित समाधान में संपादित कर सकते हैं?
 – 
einpoklum
10 फरवरी 2018, 22:01
मुझे नहीं लगता कि मैं इसे पार्स करने के बारे में किसी भी प्रकार की गारंटी बनाने के लिए हस्ताक्षर उत्पन्न/गणना करने के तरीके के बारे में पर्याप्त जानता हूं - एमएसवीसी से परिचित किसी के लिए यह एक बेहतर काम होगा। यदि आप किसी को अधिक उपयुक्त नहीं पाते हैं, तो मैं एक प्रयास करूँगा। जिस तरह से यह काम करता प्रतीत होता है, आप foo के बाद समान रूप से कई उद्घाटन और समापन <> जोड़े की अपेक्षा करेंगे - लेकिन एक प्रकार T (W<X>::*operator<)(Y<Z>), आदि हो सकता है - मुझे यकीन है कि वहां हैं अन्य चेतावनियां (मेरे सिंटैक्स हाइलाइटर में 'प्रयोगात्मक' टेम्पलेट है जो कई मुद्दों के साथ हाइलाइट करता है, इसलिए झिझक।)
 – 
John P
13 फरवरी 2018, 08:10
सामान्य तौर पर मेरा मानना ​​​​है कि मुझे ऐनक पर एक अच्छी नज़र डालनी होगी - जाहिर है कि कंपाइलर किसी तरह प्रबंधन करते हैं, और अस्पष्टता वाले कुछ मामलों में इसे हल करने के लिए विशेष सिंटैक्स होता है, उदा। सबसे कष्टप्रद पार्स। मैं गलत उत्तर खड़े रहने के बजाय इसे सही करना चाहता हूं। एक तरफ, अगर __PRETTY_FUNCTION__ आदि के लिए कोई मामला है, तो __PRETTY_THIS__ या कुछ और के लिए एक मामला होना चाहिए, है ना? हम जो कर रहे हैं वह 'गलत' आईएमएचओ है।
 – 
John P
13 फरवरी 2018, 08:17

एक वैकल्पिक उत्तर जिसका उपयोग टेम्पलेट में किया जा सकता है, अब यह g++ और clang++ और msvc के साथ चल सकता है।

ऊपर दिए गए उत्तर @einpoklum से संशोधित: https://stackoverflow.com/a/56600402/12529885

#include <iostream>
#include <string_view>

template<typename T>
struct TypeName {
    constexpr static std::string_view fullname_intern() {
        #if defined(__clang__) || defined(__GNUC__)
            return __PRETTY_FUNCTION__;
        #elif defined(_MSC_VER)
            return __FUNCSIG__;
        #else
            #error "Unsupported compiler"
        #endif
    }
    constexpr static std::string_view name() {
        size_t prefix_len = TypeName<void>::fullname_intern().find("void");
        size_t multiple   = TypeName<void>::fullname_intern().size() - TypeName<int>::fullname_intern().size();
        size_t dummy_len  = TypeName<void>::fullname_intern().size() - 4*multiple;
        size_t target_len = (fullname_intern().size() - dummy_len)/multiple;
        std::string_view rv = fullname_intern().substr(prefix_len, target_len);
        if (rv.rfind(' ') == rv.npos)
            return rv;
        return rv.substr(rv.rfind(' ')+1);
    }

    using type = T;
    constexpr static std::string_view value = name();
};

namespace s1 {
    class MyClass;
}

//Both MSVC, G++ and Clang++ have passed test.
int main () {
    static_assert(TypeName<s1::MyClass>::value == "s1::MyClass");
    std::cout<<"FULLNAME> "<<TypeName<void>::fullname_intern()<<std::endl;
    std::cout<<"TYPETEST> '"<<TypeName<s1::MyClass>::value<<"' == 's1::MyClass'"<<std::endl;
    return 0;
}

ध्यान दें कि:

क्लैंग++ में पूरा नाम: static std::string_view TypeName<void>::fullname_intern() [T = void]

G++ में पूरा नाम: static constexpr std::string_view TypeName<T>::fullname_intern() [with T = void; std::string_view = std::basic_string_view<char>]

MSVC में पूरा नाम: class std::basic_string_view<char,struct std::char_traits<char> > __cdecl TypeName<void>::fullname_intern(void)(लेकिन 'कक्षा s1::MyClass' नहीं 's1::MyClass' यहाँ)

-1
vrqq 30 जून 2021, 19:56