如何调整我的功能模板,以便它们可以部分专业化?#34;?

时间:2014-03-17 05:56:31

标签: c++ templates c++11 template-specialization

现在我知道功能模板的部分特化是不存在的(如果我理解正确,推理就是如果他们这样做,他们会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所说)?但是,如何编写语法仍然有点模糊!

1 个答案:

答案 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();
}