首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++获取模板中类型的名称

C++获取模板中类型的名称
EN

Stack Overflow用户
提问于 2009-06-28 18:30:59
回答 10查看 154.2K关注 0票数 92

我正在编写一些模板类来解析一些文本数据文件,因此很可能大多数解析错误都是由于数据文件中的错误造成的,这些错误大部分不是由程序员编写的,因此需要一个关于应用程序无法加载的好消息,例如:

分析example.txt时出现

错误。MySectiomKey的值(“notaninteger”)不是有效的int

我可以从传递给模板函数和类中的成员变量的参数中计算出文件名、节名和键名,但是我不确定如何获得模板函数试图转换为的类型的名称。

我当前的代码看起来像这样,只对普通字符串和以下内容进行了专门化:

代码语言:javascript
运行
复制
template<typename T> T GetValue(const std::wstring &section, const std::wstring &key)
{
    std::map<std::wstring, std::wstring>::iterator it = map[section].find(key);
    if(it == map[section].end())
        throw ItemDoesNotExist(file, section, key)
    else
    {
        try{return boost::lexical_cast<T>(it->second);}
        //needs to get the name from T somehow
        catch(...)throw ParseError(file, section, key, it->second, TypeName(T));
    }
}

我不想为数据文件可能使用的每一种类型都做特定的重载,因为有很多类型的重载...

另外,我需要一个不会引起任何运行时开销的解决方案,除非发生异常,即完全编译时解决方案是我想要的,因为这个代码被调用了很多次,加载时间已经变得有点长了。

编辑:好的,这是我想出的解决方案:

我有一个包含以下内容的类型.h

代码语言:javascript
运行
复制
#pragma once
template<typename T> const wchar_t *GetTypeName();

#define DEFINE_TYPE_NAME(type, name) \
    template<>const wchar_t *GetTypeName<type>(){return name;}

然后,我可以使用DEFINE_TYPE_NAME宏来为我需要处理的每种类型导入cpp文件(例如,在定义要开始的类型的cpp文件中)。

然后链接器能够找到合适的模板专门化,只要它是在某个地方定义的,或者抛出一个链接器错误,这样我就可以添加类型了。

EN

回答 10

Stack Overflow用户

回答已采纳

发布于 2009-06-28 19:21:30

Jesse Beder的解决方案可能是最好的,但如果你不喜欢typeid给你的名字(例如,我认为gcc给你的名字是乱码),你可以这样做:

代码语言:javascript
运行
复制
template<typename T>
struct TypeParseTraits;

#define REGISTER_PARSE_TYPE(X) template <> struct TypeParseTraits<X> \
    { static const char* name; } ; const char* TypeParseTraits<X>::name = #X


REGISTER_PARSE_TYPE(int);
REGISTER_PARSE_TYPE(double);
REGISTER_PARSE_TYPE(FooClass);
// etc...

然后像这样使用它

代码语言:javascript
运行
复制
throw ParseError(TypeParseTraits<T>::name);

编辑:

您也可以将两者结合起来,将name更改为一个默认调用typeid(T).name()的函数,然后只针对那些不可接受的情况进行专门处理。

票数 44
EN

Stack Overflow用户

发布于 2009-06-28 18:42:03

解决方案是

代码语言:javascript
运行
复制
typeid(T).name()

它返回std::type_info

票数 91
EN

Stack Overflow用户

发布于 2013-10-02 02:59:27

typeid(T).name()是实现定义的,不保证人类可读的字符串。

正在读取cppreference.com

返回一个实现定义的以null结尾的字符串,其中包含类型的名称。不能保证,特别是,返回的字符串对于几种类型可能是相同的,并且在同一程序的调用之间发生变化。

..。

使用像gcc和clang这样的编译器,返回的字符串可以通过管道通过c++filt -t转换为人类可读的形式。

但在某些情况下,gcc不会返回正确的字符串。例如,在我的机器上,我有一个带有-std=c++11的gcc,在模板函数中,typeid(T).name()"unsigned int"返回"j"。这就是所谓的乱名。要获取真实类型名,请使用 abi::__cxa_demangle()函数(仅限gcc):

代码语言:javascript
运行
复制
#include <string>
#include <cstdlib>
#include <cxxabi.h>

template<typename T>
std::string type_name()
{
    int status;
    std::string tname = typeid(T).name();
    char *demangled_name = abi::__cxa_demangle(tname.c_str(), NULL, NULL, &status);
    if(status == 0) {
        tname = demangled_name;
        std::free(demangled_name);
    }   
    return tname;
}
票数 53
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1055452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档