2016-11-25 99 views
11

我有一個函數類方法的C++函數錯位的名字,而ValueHolder :: PRINTVALUE得到在編譯時(或運行時)

class ValueHolder { 

public: 
    void printValue(); 
} ; 

如何確定在編譯時(或運行時),它的重整名稱。

比如我想做到這一點:

const char *mangled_name = GetMangledNameOfSymbol(&ValueHolder::printValue); 

該功能可能會返回像一個字符串:

"_ZN11ValueHolder10printValueEv" 

按@Marco答:前提是一個現代化的編譯器。一個支持typeid,並打開標誌啓用此功能。

我也會接受一個可以在GCC & Clang實用工作的答案,以及MSVC的一個存根。

回答

-2

那麼你可以做的是使用g ++編譯你的C++程序並獲得.o文件。在如此獲得的.o文件上運行'nm'命令以獲取重名的名稱!這種方法在Linux系統上是可行的。

8

有這樣做的沒有標準的方式,根據[lib.type.info]

類TYPE_INFO介紹類型由實現產生的信息。這個類的對象有效地存儲一個指向該類型名稱的指針,以及一個適合比較兩種類型的相等或整理順序的編碼值。類型的名稱,編碼規則和整理順序都是未指定的,並且程序之間可能會有所不同。

和你的編譯器實現,你可以使用typeid(type/expression).name()但無處指定或強制執行這個名字將被裝飾(這是實現定義)。它也取決於使用的編譯標誌(謝謝malat)。

實施例:

class ValueHolder { 

public: 
    void printValue(); 
}; 


int main() { 
    std::cout << typeid(&ValueHolder::printValue).name(); 
} 

gcc7.0

M11ValueHolderFvvE

clang4.0

M11ValueHolderFvvE

MSVC14

無效(__cdecl而ValueHolder :: *)(無效)__ptr64

+0

還請澄清,它不僅依賴於編譯器+版本,而且編譯標誌(如STD = C++ 11的std :: string,和/或類似的東西'-DGLIBCXX_DEBUG') – malat

+0

@謝謝,我會將這一部分添加到答案中。 –

+0

這是一個很好的答案。我要改變這個問題只是一點點,以反映使用現代編譯器。 – iamacomputer

3

我加入了一個答案,但我不打算將其標記爲正確的。它不完整。太大以至於無法添加評論。這是我能做的事情,但我正在尋找更好的方法。而且,是的,非常俗氣 - 哈克。但是我認爲有一些API在某些地方會保證工作(如果在整個項目中使用單個編譯器),這些API雖然仍然會有點嚴重。

template<typename R, typename C, typename... A> 
struct MemberFunctionPointer 
{ 
    typedef R Return; 
    typedef C Class; 
}; 

template<typename R, typename C, typename... A> 
constexpr auto inferMemberFunctionPointer(R (C::*method)(A...)) 
{ 
    return MemberFunctionPointer<R,C,A...>{}; 
} 

template<typename M, M m, typename... A> 
class GenerateMethodSignature 
{ 
    typedef typename decltype(inferMemberFunctionPointer(m))::Class T; 
    typedef typename decltype(inferMemberFunctionPointer(m))::Return R; 


public: 
    static const char *mangledName (const char *fs) 
    { 
     const char *ts = typeid(T).name(); 
     const char *rs = typeid(R).name(); 
     const char *ms = typeid(M).name(); 

     std::string r = "_Z"; 
     if (ts[0] != 'N') 
      r += "N"; 
     r += ts; 
     if (ts[0] == 'N') 
      r.pop_back(); 

     r += std::to_string(strlen(fs)); 
     r += fs; 
     r += "E"; 

     r += ms + strlen ("M") + strlen(ts) + strlen ("F") + strlen(rs); 
     r.pop_back(); 

     printf("calculated signature %s\n", r.c_str()); 

     // this is very bad but... for demonstration purposes 
     return strdup(r.c_str()); 
    } 
} ; 

namespace MyNamespace { 
namespace MySubNamespace { 
class MyClass 
{ 
public: 
    int MyFunction (int myarg); 
} ; 
} // namespace 
} // namespace 

#define ExportSignature(T, M) GenerateMethodSignature<decltype(&T::M), &T::M>::mangledName(#M) 
const char *myMethodSignature = ExportSignature(MyNamespace::MySubNamespace::MyClass, MyFunction); 
+0

看起來很有希望。但似乎在所有情況下都無法正常工作,例如嘗試將MyFunction的返回類型更改爲std :: string。 – hedayat

+0

在這種情況下,B5cxx11後綴被添加到函數名稱中。 此外,如果您還將參數類型更改爲std :: string,則輸出完全被擰緊... – hedayat

+0

是的,這個答案並不完整,只是一個演示。我希望有人會有更好的方式,而不是像哈克一樣。 – iamacomputer