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)
似乎额外的括号使模板参数无效.有没有办法解决?
此外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)
你可以使用typedef:
typedef std::map<int, int> int_map;
SET_TYPE_NAME(int_map, "TheMap");
Run Code Online (Sandbox Code Playgroud)
boost的BOOST_FOREACH遭遇同样的问题.
前一段时间(在网上搜索实用程序时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页面上的许多答案实质上是"宏都很愚蠢".但我不会发表评论.)
| 归档时间: |
|
| 查看次数: |
6058 次 |
| 最近记录: |