现在我知道功能模板的部分特化是不存在的(如果我理解正确,推理就是如果他们这样做,他们会never be used)。
但是我有一个特定的功能模板,我现在大量使用,如下所示:
template <typename>
char const* TypeName() {
return "UNDECLARED TYPENAME";
}
#define TYPENAME(...) \
GET_MACRO(__VA_ARGS__, TYPENAME32, TYPENAME31, TYPENAME30, TYPENAME29, \
TYPENAME28, TYPENAME27, TYPENAME26, TYPENAME25, TYPENAME24, \
TYPENAME23, TYPENAME22, TYPENAME21, TYPENAME20, TYPENAME19, \
TYPENAME18, TYPENAME17, TYPENAME16, TYPENAME15, TYPENAME14, \
TYPENAME13, TYPENAME12, TYPENAME11, TYPENAME10, TYPENAME9, \
TYPENAME8, TYPENAME7, TYPENAME6, TYPENAME5, TYPENAME4, TYPENAME3, \
TYPENAME2, TYPENAME1)(__VA_ARGS__)
#define TYPENAME1(x) \
template<> char const* TypeName<x>() { return #x; }
#define TYPENAME2(x, y) \
template<> char const* TypeName<x, y>() { return #x "," #y; }
#define TYPENAME3(x, y, z) \
template<> char const* TypeName<x, y, z>() { return #x "," #y "," #z; }
#define TYPENAME4(x, y, z, w) \
template<> char const* TypeName<x, y, z, w>() { return #x "," #y "," #z "," #w; }
// ... and so on and so forth
GET_MACRO在哪里
#define GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,NAME,...) NAME
好的,所以这一切都运行得很好,花花公子,只要我的代码中的任何地方我都放置,例如TYPENAME(std::unordered_map<std::vector<typeA>, std::map<int, std::string>>)
然后我就可以将编译时代码评估为TypeName<T>()
T
std::unordered_map<std::vector<typeA>, std::map<int, std::string>>
为"std::unordered_map<std::vector<typeA>, std::map<int, std::string>>"
。template <> char const* TypeName<...>() { return ... }
现在效果非常好。
为了澄清,TYPENAME宏的唯一目的就是让我可以避免输入TypeName<std::unordered_map<K,V>>()
。它适用于干燥。它是一组精心设计的宏,因为这些令人讨厌的逗号往往是类型。
现在,我想声明一些未完全指定的模板。例如,我想为TypeName<typeA>
和TypeName
声明(通过我的宏)模板,并对前一个函数的评估调用TypeName和TypeName来确定为字符串返回的内容。
然而,似乎我遇到了限制,因为我显然不应该能够通过功能模板来实现这一点。如果我想做这样的事情,似乎整个宏集都需要被抛出窗外。
我可以使用课程模板吗?我确实希望在编译时将这一切都工作,但是如果有办法这样做,那么在第一次访问时(在运行时)构建并缓存动态字符串,那也应该足够快,我可以处理它。
我只是不想显式声明完全限定类型的模板,我希望operator <<
能够智能地组合字符串(就像我已经可以使用例如typename T
)。
我想知道我是否只是做了一些非常愚蠢的事情,应该让我的{{1}}作为TypeName的函数参数而不是模板参数化(如Herb Sutter所说)?但是,如何编写语法仍然有点模糊!
答案 0 :(得分:1)
您应该可以使用类模板执行您想要的操作:
template <typename...> struct helper_typename;
#define TYPENAME1(x) \
template<> struct helper_typename<x> \
{ static char const* TypeName() { return #x; } };
#define TYPENAME2(x, y) \
template<> struct helper_typename<x, y> \
{ static char const* TypeName() { return #x "," #y; } };
//...
// partial specialization for std::unordered_map
template <typename K, typename V>
struct helper_typename<std::unordered_map<K, V>>
{
static char const* TypeName()
{
static std::string s = std::string("std::unordered_map<")
+ helper_typename<K>::TypeName() + ", "
+ helper_typename<V>::TypeName() + ">";
return s.c_str();
}
};
template <typename... Ts> char const* TypeName()
{
// forward to the correct (partial) specialized struct.
return helper_typename<Ts...>::TypeName();
}