簡體   English   中英

是否可以從C ++中的模板類型中獲取char *名稱

[英]Is it possible to get a char* name from a template type in C++

我想獲取模板類型的字符串名稱(const char *)。 不幸的是我無法訪問RTTI。

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return /* magic goes here */; }
}

所以

SomeClass<int> sc;
sc.GetClassName();   // returns "int"

這可能嗎? 我找不到辦法,即將放棄。 謝謝您的幫助。

不,它也無法使用typeid可靠。 它將為您提供一些取決於編譯器實現的內部字符串。 像“int”這樣的東西,但“i”也常見於int

順便說一句,如果你想要的只是比較兩種類型是否相同,你不需要先將它們轉換為字符串。 你可以這樣做

template<typename A, typename B>
struct is_same { enum { value = false }; };

template<typename A>
struct is_same<A, A> { enum { value = true }; };

然后呢

if(is_same<T, U>::value) { ... }

Boost已經有了這樣一個模板,下一個C ++標准也將有std::is_same

手動注冊類型

你可以專注於這樣的類型:

template<typename> 
struct to_string {
    // optionally, add other information, like the size
    // of the string.
    static char const* value() { return "unknown"; }
};

#define DEF_TYPE(X) \
    template<> struct to_string<X> { \
        static char const* value() { return #X; } \
    }

DEF_TYPE(int); DEF_TYPE(bool); DEF_TYPE(char); ...

所以,你可以像使用它一樣

char const *s = to_string<T>::value();

當然,如果您希望在類型未知的情況下獲得編譯時錯誤,也可以刪除主模板定義(並僅保留前向聲明)。 我把它包括在這里完成。

我之前使用過char const *的靜態數據成員,但是它們會導致一些復雜的問題,比如在哪里放置聲明的問題,等等。 像上面這樣的類專業化很容易解決問題。

自動,取決於GCC

另一種方法是依賴編譯器內部。 在GCC中,以下給出了合理的結果:

template<typename T>
std::string print_T() {
    return __PRETTY_FUNCTION__;
}

返回std::string

std::string print_T() [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]

一些與find混合的substr magic會給你你想要的字符串表示。

非常簡單的解決方案:只需將一個字符串對象傳遞給SomeClass的構造函數,該構造函數說明類型是什么。

例:

#define TO_STRING(type) #type
SomeClass<int> s(TO_STRING(int));

只需存儲它並將其顯示在GetClassName的實現中。

稍微復雜的解決方案,但仍然很容易:

#define DEC_SOMECLASS(T, name) SomeClass<T> name;  name.sType = #T; 

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return sType.c_str(); }
    std::string sType;
};


int main(int argc, char **argv)
{
    DEC_SOMECLASS(int, s);
    const char *p = s.GetClassName();

    return 0;
}

模板非類型解決方案:

您還可以創建自己的類型ID,並具有轉換為ID和字符串表示形式的函數。

然后,當您將類型聲明為模板非類型參數時,可以傳遞ID:

template< typename T, int TYPEID>
struct SomeClass
{
    const char* GetClassName() const { return GetTypeIDString(TYPEID); }
};


...

SomeClass<std::string, STRING_ID> s1;
SomeClass<int, INT_ID> s2;

你可以嘗試這樣的事情(警告這只是我的頭腦,因此可能存在編譯錯誤等。)

template <typename T>
const char* GetTypeName()
{
    STATIC_ASSERT(0); // Not implemented for this type
}

#define STR(x) #x
#define GETTYPENAME(x) str(x) template <> const char* GetTypeName<x>() { return STR(x); }

// Add more as needed
GETTYPENAME(int)
GETTYPENAME(char)
GETTYPENAME(someclass)

template< typename T >
struct SomeClass
{
    const char* GetClassName() const { return GetTypeName<T>; }
}

這適用於您GETTYPENAME(type)添加GETTYPENAME(type)行的任何類型。 它的優點是它可以在不修改您感興趣的類型的情況下工作,並且可以使用內置和指針類型。 它確實有一個明顯的缺點,即您必須為每個要使用的類型添加一行。

如果不使用內置的RTTI,你將不得不在某處自己添加信息,Brian R. Bondy的答案或者dirkgently將會起作用。 除了我的回答,您還有三個不同的位置來添加該信息:

  1. 在對象創建時使用SomeClass<int>("int")
  2. 在使用dirkgently的編譯時RTTI或虛函數的類中
  3. 使用模板使用我的解決方案。

這三個都可以工作,這只是一個問題,你最終會遇到最困難的問題。

你無法訪問RTTI,這是否意味着你不能使用typeid(T).name()? 因為這幾乎是使用編譯器幫助完成它的唯一方法。

類型具有唯一名稱是非常重要的,還是以某種方式保留名稱? 如果是這樣,你應該考慮給它們一些比代碼中聲明的類名更強大的東西。 您可以通過將兩個類放在不同的名稱空間中來為它們提供相同的非限定名稱。 您還可以在Windows上的兩個不同的DLL中放置兩個具有相同名稱的類(包括名稱空間限定),因此您還需要將DLL的標識包含在名稱中。

當然,這完全取決於你要對琴弦做些什么。

你可以自己添加一些魔法。 就像是:

#include <iostream>

#define str(x) #x
#define xstr(x) str(x)
#define make_pre(C) concat(C, <)
#define make_post(t) concat(t, >)

#define make_type(C, T) make_pre(C) ## make_post(T)
#define CTTI_REFLECTION(T, x)  static std::string my_typeid() \
                               { return xstr(make_type(T, x)); }


// the dark magic of Compile Time Type Information (TM)
#define CTTI_REFLECTION(x)  static const char * my_typeid() \
                                  { return xstr(make_type(T, x)); }

#define CREATE_TEMPLATE(class_name, type) template<> \
                                    struct class_name <type>{ \
                                        CTTI_REFLECTION(class_name, type) \
                                    }; 

// dummy, we'll specialize from this later
template<typename T> struct test_reflection;

// create an actual class
CREATE_TEMPLATE(test_reflection, int)

struct test_reflection {
  CTTI_REFLECTION(test_reflection)
};

int main(int argc, char* argv[])
{
    std::cout << test_reflection<int>::my_typeid();
}

我會做的檢查一個static函數(因此非const )。

不,對不起

如果你嘗試在int上使用它,RTTI甚至都不會編譯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM