2016-11-25 183 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