std::allocator >::_Alloc>::value_type>::value_type *
?
将param的类型显示为:
?
const std::_Simple_types<...>::value_type *const &
?
这个显示没有T的那么吓人了,中间的…只是意味着IDE告诉你,我将T的类型显示用…替代了。
?
template?
void f(const T& param)?
{?
TD TType; // elicit errors containing?
TD paramType; // T's and param's types?
…?
}
?
我的理解是大多数显示在这里的东西是由于typedef造成的,一旦你通过typedef来获得潜在的类型信息,你会得到你所寻找的,但需要做一些工作来消除IDE最初显示出的一些类型,幸运的话, 你的IDE编辑器会对这种代码处理的更好。
?
(My understanding is that most of what’s displayed here is typedef cruft and that?
once you push through the typedefs to get to the underlying type information,?
you get what you’re looking for, but having to do that work pretty much eliminates?
any utility the display of the types in the IDE originally promised. With any luck,?
your IDE editor does a better job on code like this.)
?
在我的经验中,使用编译器的错误诊断信息来知道变量被推导出的类型是相对可靠的方法,利用修订之后的函数模板f来实例化只是声明的模板TD,修订之后的f看起来像下面这样
?
template?
void f(const T& param)?
{?
TD TType; // 引起错误的信息包括了?
TD paramType; //T和param的类型?
}
GNU,Clang和Microsoft的编译器都提供了带有T和param正确类型的错误信息,当时显示的格式各有不同,例如在GUN中(格式经过了一点轻微的修改)
?
error: 'TD TType' has incomplete type?
error: 'TD paramType' has incomplete?
type
?
?
?
除了typeid
?
如果你想要在运行时获得更正确的推导类型是什么,我们已经知道typeid并不是一个可靠的方法,一个可行的方法是自己实现一套机制来完成从一个类型到它的表示的映射,概念上这并不困难,你只需要利用type trait和模板元
编程的方法来将一个完整类型拆分开(使用std::is_const,std::is_ponter,std::is_lvalue_reference之类的type trait),你还需要自己完成类型的每一部分的字符串表示(尽管你依旧需要typeid和std::type_info::name来产生用户自定义格式的字符串表达)
?
?
?
如果你经常需要使用这个方法,并且认为花费在调试,文档,维护上的努力是值得的,那么这是一个合理的方法(If you’d use such a facility often enough to justify the effort needed to write, debug,document, and maintain it, that’s a reasonable approach),但是如果你更喜欢那些移植性不是很强的但是能轻易实现并且提供的结果比typeid更好的代码的, 你需要注意到很多编译器都提供了语言的扩展来产生一个函数签名的字符串表达,包括从模板中实例化的函数,模板和模板参数的类型。
?
?
?
例如,GNU和Clang都支持_PRETTY_FUNCTION_,Microsoft支持了_FUNCSIG_,他们代表了一个变量(在 GNU和Clang中)或是一个宏(在Microsoft中),如果我们将模板f这么实现的话
?
复制代码
template?
void f(const T& param)?
{
?
#if defined(__GNUC__) //对于GNU和?
std::cout << __PRETTY_FUNCTION__ << '\n'; // Clang?
#elif defined(_MSC_VER)?
std::cout << __FUNCSIG__ << '\n'; //对于Microsoft?
#endif?
…?
}
复制代码
像之前那样调用f
?
std::vector createVec(); // 工厂函数?
const auto vw = createVec(); // 用工厂函数来实例化vw?
if (!vw.empty()) {?
f(&vw[0]); //调用f?
}
在GNU中我们得到了以下的结果
?
void f(const T&) [with T = const Widget*]
?
告诉我们T的类型被推导为const Widget*(和我们用typeid得到的结果一样,但是前面没有PK的编码和类名前面的6),同时它也告诉我们f参数类型是const T&,如果我们按照这个格式扩展T,我们得到f的类型是const Widget * const&,和typeid的答案不同,但是和使用未定义的模板,产生的错误诊断信息中的类型信息一致,所以它是正确的。
?
?
?
Microsoft的 _FUNCSIG_提供了以下的输出:
?
void __cdecl f(const class Widget *const