मैं संकलन समय पर एक प्रकार के नाम का उपयोग करना चाहता हूं। उदाहरण के लिए, मान लीजिए मैंने लिखा है:
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*
है, कॉन्स्टेक्स नहीं...
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++ के लिए काम करता है)
__FUNCSIG__
के साथ कुछ ऐसा ही लागू किया जा सकता है।
__FUNCSIG__
का परीक्षण किया। ऐसा लगता है कि जीसीसी के हाइब्रिड आउटपुट के विपरीत, पूरी तरह से प्रतिस्थापित/बाध्य प्रकारों को उत्सर्जित करता है, जैसे कि फ़ंक्शन को स्पष्ट रूप से तत्काल चालू किया गया था। उदाहरण के लिए: void __cdecl foo<double>(const double &)
, जो एक नज़र में मेरे लिए कम उपयोगी लगता है। (जीसीसी अभी भी आश्रित बनाम मुक्त प्रकारों के बीच कुछ अजीब अंतर करता है, या शायद घटाया बनाम गणना प्रकार, जब प्रतिस्थापन प्रदर्शन करते हैं।) मुझे लगता है कि प्रतिबिंब अत्यधिक कम और कम समर्थित है, esp। अवधारणाओं के साथ अब तक क्षितिज पर ...
foo
के बाद समान रूप से कई उद्घाटन और समापन <>
जोड़े की अपेक्षा करेंगे - लेकिन एक प्रकार T (W<X>::*operator<)(Y<Z>)
, आदि हो सकता है - मुझे यकीन है कि वहां हैं अन्य चेतावनियां (मेरे सिंटैक्स हाइलाइटर में 'प्रयोगात्मक' टेम्पलेट है जो कई मुद्दों के साथ हाइलाइट करता है, इसलिए झिझक।)
__PRETTY_FUNCTION__
आदि के लिए कोई मामला है, तो __PRETTY_THIS__
या कुछ और के लिए एक मामला होना चाहिए, है ना? हम जो कर रहे हैं वह 'गलत' आईएमएचओ है।
एक वैकल्पिक उत्तर जिसका उपयोग टेम्पलेट में किया जा सकता है, अब यह 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' यहाँ)
संबंधित सवाल
जुड़े हुए प्रश्न
नए सवाल
c++
C ++ एक सामान्य-प्रयोजन प्रोग्रामिंग भाषा है। यह मूल रूप से C के विस्तार के रूप में डिज़ाइन किया गया था और इसमें एक समान सिंटैक्स है, लेकिन यह अब पूरी तरह से अलग भाषा है। C ++ कंपाइलर के साथ संकलित कोड के बारे में प्रश्नों के लिए इस टैग का उपयोग करें। विशिष्ट मानक संशोधन [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] या [C ++ 23], आदि से संबंधित प्रश्नों के लिए संस्करण-विशिष्ट टैग का उपयोग करें। ।
type_name_length<T>
के साथ क्या करना चाहते हैं जिसकी आपको संकलन समय पर आवश्यकता है? कंपाइलर केवलstrlen()
का मूल्यांकन करने और यदि संभव हो तो आपको स्थिरांक देने के बारे में बहुत अच्छे हैं।