我正在编写一些模板类来解析一些文本数据文件,因此很可能大多数解析错误都是由于数据文件中的错误造成的,这些错误大部分不是由程序员编写的,因此需要一个关于应用程序无法加载的好消息,例如:
分析example.txt时出现
错误。MySectiomKey的值(“notaninteger”)不是有效的int
我可以从传递给模板函数和类中的成员变量的参数中计算出文件名、节名和键名,但是我不确定如何获得模板函数试图转换为的类型的名称。
我当前的代码看起来像这样,只对普通字符串和以下内容进行了专门化:
template<typename T> T GetValue(const std::wstring §ion, 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
#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文件中)。
然后链接器能够找到合适的模板专门化,只要它是在某个地方定义的,或者抛出一个链接器错误,这样我就可以添加类型了。
发布于 2009-06-28 19:21:30
Jesse Beder的解决方案可能是最好的,但如果你不喜欢typeid给你的名字(例如,我认为gcc给你的名字是乱码),你可以这样做:
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...
然后像这样使用它
throw ParseError(TypeParseTraits<T>::name);
编辑:
您也可以将两者结合起来,将name
更改为一个默认调用typeid(T).name()
的函数,然后只针对那些不可接受的情况进行专门处理。
发布于 2009-06-28 18:42:03
发布于 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):
#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;
}
https://stackoverflow.com/questions/1055452
复制相似问题