为什么声明出现在一个混乱的符号名中
Why is declval present in a mangled symbol name?
我正在使用GCC (4.9.2) abi::__cxa_demangle,我遇到了一个无法demangle特定符号名的情况。
符号是:
_ZNK12DebugWrapperIR5TestClsE5getIdIIEEEDTcldtcl7declvalIS1_EEL_ZNKS0_5getIdEvEspfp_EEDpOT_
我很惊讶在这里看到declval
这个函数是用这个宏定义的:
template <typename WrappedType>
class DebugWrapper
{
private:
WrappedType VALUE;
std::string NAME;
mutable std::string CALLER;
public:
...
#define WRAP_CONST_FUNCTION(name, enterLogging, exitLogging)
template <typename ...Args>
auto name(Args&&... args) const -> decltype(std::declval<WrappedType>().name(args...))
{
struct dummy
{
const char* const FUNCTION = nullptr;
const std::string& CALLER;
const WrappedType& VALUE;
dummy( const char* const input,
const std::string& caller,
const WrappedType& value):
FUNCTION(input), CALLER(caller), VALUE(value)
{
enterLogging;
}
~dummy()
{
exitLogging;
}
}dummy(#name, CALLER, VALUE);
return VALUE.name(args...);
}
WRAP_CONST_FUNCTION(getId, <whatever>, <whatever>)
...
};
我也做了一个快速搜索,通过itanc++ abi规范声明,但没有结果。
它为什么在那里?为什么我不能这样做呢?
模板函数需要将其返回类型出现在修改后的名称中,因为模板函数可以仅在返回类型上重载。一个更简单的例子是
template <typename T> void f() { }
template <typename T> auto g() -> decltype(f<T>()) { }
inline void h() { }
int main() { g<int>(); h(); }
编译并检查输出,我看到:
<>之前$ g++ -c h.cc -std=c++11 && nm h.o | c++filt0000000000000000 T主0000000000000000 W decltype ((f)()) g()0000000000000000 W h()之前您可以在那里看到g
的返回类型,但h
没有。事实上,h
已经不是一个模板函数,这意味着在相同的命名空间中不可能有另一个具有相同参数的函数h
。
这也是为什么getId
在你的名字中出现了两次。其中一个是名称本身,另一个来自它在返回类型中的外观。
declval
在这里并不特殊,这就是为什么它没有在c++ ABI中调用的原因。任何函数,库或用户,都以同样的方式处理。
至于它为什么不动,很难说。在您的问题中生成混乱的名称的真实代码示例将在这里有所帮助,但是5TestCls
看起来错误,因为名称前面的数字表示长度,并且我确实得到了TestCls
应该是全名的印象。如果这确实是名称,则请求失败,因为修改后的名称无效。
根据您在评论中发布的完整示例,我可以提出一个简化的程序,似乎是成员访问操作符没有被demangler正确处理:
extern struct A { void f(); static void g(); } a;
template <typename...T> auto f(T...t) -> decltype(a.f(t...));
template <typename...T> auto g(T...t) -> decltype(A::g(t...));
int main() { f(); g(); }
<>以前g++化c++ 11美元迂腐- c h.cc & & h.o & & nm - c h.o0000000000000000 T主U _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_U _Z1gIJEEDTclL_ZN1A1gEvEspfp_EEDpT_0000000000000000 T主U _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_U decltype (A::g({parm#1}…))g<>() _Z1fIJEEDTcldtL_Z1aEL_ZN1A1fEvEspfp_EEDpT_
和_Z1gIJEEDTclL_ZN1A1gEvEspfp_EEDpT_
之间的差异在一些额外的空格中更加明显:
唯一的区别是f
、g
和dtL_Z1aE
。
Itanium c++ ABI指定x.y
被修改为dt <expression> <unresolved-name>
。这里,<expression>
是L_Z1aE
。这部分看起来不错。这表示a
全局变量的"混乱"(不是真正的)名称。但是<unresolved-name>
就是_ZN1A1fEvE
。这是错误的。这对于decltype(A::g(t...))
版本是正确的,其中函数调用操作符的最左边的操作数可以通过<expr-primary> ::= L <mangled-name> E
表示为一个混乱的名称,但对于decltype(a.f(t...))
版本则不是这样。它可能意味着类似A::f()
的东西,但<unresolved-name>
不应该有名称空间限定符,除非它们实际出现在源代码中,即使这样,也只能使用特殊的前缀(sr
)。它也不应该有参数信息。<unresolved-name>
应该是1f
。
如果使用了正确的名称,则需方可以处理:
$ c++filt <<_Z1fIJEEDTcldtL_Z1aE1fspfp_EEDpT_Decltype ((a.f)({parm#1}…))f<>()
clang确实会生成正确的名称,在Coliru上可以看到,只需在命令调用中将g++
更改为clang++
。您可以将此作为bug报告给GCC开发人员。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 在c++中用vector填充一个简单的动态数组
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 预处理器:插入结构名称中的前一个行号
- 我在c++代码中生成了一个运行时#3异常
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 从链接列表c++中删除一个项目
- 告诉一个 const char 数组,除了编译时 C 样式的字符串外,它不以 '