如何将多参数模板传递给宏?

Pau*_*nta 12 c++ macros templates

说我有这样的宏:

#define SET_TYPE_NAME(TYPE, NAME) \
    template<typename T>          \
    std::string name();           \
                                  \
    template<>                    \
    std::string name<TYPE>() {    \
        return NAME;              \
    }
Run Code Online (Sandbox Code Playgroud)

如果我传递一个具有多个参数的模板,这将无效,因为其中的逗号<int, int>被解释为分隔参数,而不是模板参数.

SET_TYPE_NAME(std::map<int, int>, "TheMap")
// Error: macro expects two arguments, three given
Run Code Online (Sandbox Code Playgroud)

这样做似乎可以解决这个问题:

SET_TYPE_NAME((std::map<int, int>), "TheMap")
Run Code Online (Sandbox Code Playgroud)

但现在出现了另一个问题,我真的没想到的问题:

 template<>
 std::string name<(std::map<int, int>)>()
 // template argument 1 is invalid
Run Code Online (Sandbox Code Playgroud)

似乎额外的括号使模板参数无效.有没有办法解决?

ken*_*ytm 9

此外typedef,您可以切换参数的顺序并使用可变参数宏(需要C99或C++ 11兼容的编译器):

#define SET_TYPE_NAME(NAME, ...) \
template<typename T>          \
std::string name();           \
                              \
template<>                    \
std::string name<__VA_ARGS__>() {    \
    return NAME;              \
}
Run Code Online (Sandbox Code Playgroud)

...

SET_TYPE_NAME("TheMap", std::map<int, int>)
Run Code Online (Sandbox Code Playgroud)

  • 只是C++ 11,除非C99在我们不看的时候添加了`template`. (6认同)

hmj*_*mjd 8

你可以使用typedef:

typedef std::map<int, int> int_map;

SET_TYPE_NAME(int_map, "TheMap");
Run Code Online (Sandbox Code Playgroud)

boost的BOOST_FOREACH遭遇同样的问题.


gx_*_*gx_ 6

前一段时间(在网上搜索实用程序时Identity<T>),我到了这个页面.

简而言之,要回答这个问题,如果你没有C++ 11支持和/或不能(或者不想)使用a typedef,你可以用"正确"的方式调用你的宏:

// If an argument contains commas, enclose it in parentheses:
SET_TYPE_NAME((std::map<int, int>), "TheMap")
// For an argument that doesn't contain commas, both should work:
SET_TYPE_NAME((SomeType1), "TheType1")
SET_TYPE_NAME(SomeType2, "TheType2")
Run Code Online (Sandbox Code Playgroud)

然后去除类型周围的(可能的)不需要的括号,你可以使用这样的"帮助器":

template<typename> struct RemoveBrackets;
template<typename T> struct RemoveBrackets<void (T)> {
    typedef T Type;
};
Run Code Online (Sandbox Code Playgroud)

并在您的宏中更改行:

    std::string name<TYPE>() {    \
Run Code Online (Sandbox Code Playgroud)

至:

    std::string name< RemoveBrackets<void (TYPE)>::Type >() {    \
Run Code Online (Sandbox Code Playgroud)

(或者说,定义一个辅助宏

#define REMOVE_BRACKETS(x) RemoveBrackets<void (x)>::Type
Run Code Online (Sandbox Code Playgroud)

然后用.替换

    std::string name< REMOVE_BRACKETS(TYPE) >() {    \
Run Code Online (Sandbox Code Playgroud)

).

(有关完整的故事,请阅读上文链接的文章末尾的"更好的解决方案"一节.)

编辑:刚刚发现.但它<void X>在真正应该使用的时候使用<void (X)>(in get_first_param<void X>::type); 事实上,如果你传递一个"简单的",非括号的论证(如我上面的代码中所示),那么括号必要的SomeType2- 如果X已经被括起来,它们就不会受到伤害(例如,void ((SomeType1))相当于void (SomeType1);再次,请参阅文章).(顺便说一句,我注意到其他SO页面上的许多答案实质上是"宏都很愚蠢".但我不会发表评论.)