sol*_*old 34 c++ templates metadata stringification c-preprocessor
在C++中是否可以对模板参数进行字符串化?我试过这个:
#define STRINGIFY(x) #x
template <typename T>
struct Stringify
{
Stringify()
{
cout<<STRINGIFY(T)<<endl;
}
};
int main()
{
Stringify<int> s;
}
Run Code Online (Sandbox Code Playgroud)
但我得到的是'T',而不是'int'.似乎预处理器在模板解析之前启动.
有没有其他方法可以做到这一点?
有没有办法在模板解析后进行预处理?(编译器是VC++).
edu*_*ffy 34
你可以试试
typeid(T).name()
Run Code Online (Sandbox Code Playgroud)
编辑:根据评论修复.
Cat*_*lus 23
你可以使用一些模板魔法.
#include <iostream>
template <typename T>
struct TypeName { static const char *name; };
template <typename T>
const char *TypeName<T>::name = "unknown";
template <>
const char *TypeName<int>::name = "int";
template <typename T>
struct Stringify
{
Stringify()
{
std::cout << TypeName<T>::name << std::endl;
}
};
int main()
{
Stringify<int> s;
}
Run Code Online (Sandbox Code Playgroud)
这比RTTI(即typeinfo)更有优势- 它在编译期间得到解决; 和缺点 - 你需要自己提供类型信息(除非有一些我已经不知道的那个库;甚至可能在Boost中提供一些东西).
或者,正如Matrin York在评论中建议的那样,使用内联函数模板:
template <typename T>
inline const char* typeName(void) { return "unknown"; }
template <>
inline const char* typeName<int>(void) { return "int"; }
// ...
std::cout << typeName<T>() << std::endl;
Run Code Online (Sandbox Code Playgroud)
但是,如果您需要存储有关该特定类型的更多信息,那么类模板可能会更好.
Gui*_*ira 16
您的代码不起作用,因为负责搜索和扩展您在代码中使用的宏的预处理器不了解语言本身.它只是一个文本解析器.它在函数模板中找到STRINGIFY(T)并将其展开,远在为该模板提供类型之前.事实证明,不幸的是,你总是得到"T"而不是你期望的类型名.
正如litb建议的那样,我(很糟糕地)实现了这个`getTypeName'函数模板,它返回你传递它的类型名:
#include <iostream>
template <typename _Get_TypeName>
const std::string &getTypeName()
{
static std::string name;
if (name.empty())
{
const char *beginStr = "_Get_TypeName =";
const size_t beginStrLen = 15; // Yes, I know...
// But isn't it better than strlen()?
size_t begin,length;
name = __PRETTY_FUNCTION__;
begin = name.find(beginStr) + beginStrLen + 1;
length = name.find("]",begin) - begin;
name = name.substr(begin,length);
}
return name;
}
int main()
{
typedef void (*T)(int,int);
// Using getTypeName()
std::cout << getTypeName<float>() << '\n';
std::cout << getTypeName<T>() << '\n'; // You don't actually need the
// typedef in this case, but
// for it to work with the
// typeid below, you'll need it
// Using typeid().name()
std::cout << typeid(float).name() << '\n';
std::cout << typeid(T).name() << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码导致以下输出启用GCC标志-s("从二进制中删除所有符号"):
float
void (*)(int, int)
f
PFviiE
Run Code Online (Sandbox Code Playgroud)
所以,你看,getTypename()做了一个相当好的工作,代价是解析hack的那个乱码(我知道,这真是太可怕了).
需要考虑以下几点:
__PRETTY_FUNCTION__不同,字符串匹配可能会中断,您必须修复它.出于同样的原因,我也警告getTypeName()可能对调试有好处(并且,甚至可能甚至不好),但对于其他目的,例如比较模板中的两种类型,它肯定是坏的,坏的和坏的或类似的东西(我不知道,只是猜测某人可能会想到的......).仅将它用于调试,并且优先不在发布版本中调用它(使用宏来禁用),这样就不会使用__PRETTY_FUNCTION__,因此编译器不会为它生成字符串.尽管有这些缺点,但我想说它确实很快.第二次查找同一个类型名称时,将花费选择对包含该名称的全局std :: string的引用.而且,与之前建议的模板特化方法相比,除了模板本身之外没有其他任何东西需要声明,因此它实际上更容易使用.
Dav*_*eas 12
不,你不能在类型上工作,就好像它们是变量一样.您可以编写提取元素的typeid()并打印名称的代码,但结果值可能不是您所期望的(类型名称不是标准化的).
如果您要使用的类型数量有限,您还可以使用模板特化(以及一些宏魔术)来实现更有趣的版本:
template <typename T> const char* printtype(); // not implemented
// implement specializations for given types
#define DEFINE_PRINT_TYPE( type ) \
template<>\
const char* printtype<type>() {\
return #type;\
}
DEFINE_PRINT_TYPE( int );
DEFINE_PRINT_TYPE( double );
// ... and so on
#undef DEFINE_PRINT_TYPE
template <typename T> void test()
{
std::cout << printtype<T>() << std::endl;
}
int main() {
test<int>();
test<double>();
test<float>(); // compilation error, printtype undefined for float
}
Run Code Online (Sandbox Code Playgroud)
或者你甚至可以组合两个版本:使用typeinfo实现printtype泛型模板,然后为想要拥有更高级名称的类型提供特化.
template <typename T>
const char* printtype()
{
return typeid(T).name();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23611 次 |
| 最近记录: |